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/libimageio/Android.mk b/libs/vr/libimageio/Android.mk
new file mode 100644
index 0000000..b3b88ac
--- /dev/null
+++ b/libs/vr/libimageio/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+sourceFiles := \
+	image_io.cpp \
+	image_io_png.cpp \
+	image_io_ppm.cpp
+
+includeFiles := \
+  $(LOCAL_PATH)/include
+
+sharedLibraries := \
+	libcutils \
+	libpng
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(sourceFiles)
+LOCAL_C_INCLUDES += $(includeFiles)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(includeFiles)
+LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
+LOCAL_CFLAGS := -Wall -Wextra
+LOCAL_MODULE := libimageio
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/vr/libimageio/image_io.cpp b/libs/vr/libimageio/image_io.cpp
new file mode 100644
index 0000000..5ad6c2d
--- /dev/null
+++ b/libs/vr/libimageio/image_io.cpp
@@ -0,0 +1,92 @@
+#define LOG_TAG "ImageIo"
+
+#include <private/dvr/image_io.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+
+#include <private/dvr/image_io_base.h>
+#include <private/dvr/image_io_logging.h>
+#include <private/dvr/image_io_png.h>
+#include <private/dvr/image_io_ppm.h>
+
+namespace {
+
+// Returns true if |str| ends with |suffix|.
+bool EndsWith(const std::string& str, const std::string& suffix) {
+  if (str.length() < suffix.length())
+    return false;
+
+  return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
+}
+
+// Returns lower case copy of the input string.
+std::string ToLower(std::string str) {
+  std::transform(str.begin(), str.end(), str.begin(),
+                 [](char x) { return std::tolower(x); });
+  return str;
+}
+
+}  // namespace
+
+std::unique_ptr<ImageIoReader> ImageIoReader::Create(const char* filename) {
+  std::unique_ptr<ImageIoReader> reader;
+  std::string filename_lower = ToLower(filename);
+
+  if (EndsWith(filename_lower, ".ppm"))
+    reader.reset(new ImageIoPpmReader(filename));
+
+  if (!reader) {
+    ALOGE("Unknown/unsupported image file format.");
+    return nullptr;
+  }
+
+  return reader;
+}
+
+std::unique_ptr<ImageIoWriter> ImageIoWriter::Create(const char* filename,
+                                                     int width, int height,
+                                                     const uint8_t* image) {
+  std::unique_ptr<ImageIoWriter> writer;
+  std::string filename_lower = ToLower(filename);
+
+  if (EndsWith(filename_lower, ".ppm"))
+    writer.reset(new ImageIoPpmWriter(filename, width, height, image));
+  else if (EndsWith(filename_lower, ".png"))
+    writer.reset(new ImageIoPngWriter(filename, width, height, image));
+
+  if (!writer) {
+    ALOGE("Unknown/unsupported image file format.");
+    return nullptr;
+  }
+
+  return writer;
+}
+
+extern "C" {
+
+bool image_io_write_rgb888(const char* filename, int width, int height,
+                           const uint8_t* image) {
+  auto writer = ImageIoWriter::Create(filename, width, height, image);
+  if (!writer)
+    return false;
+  return writer->WriteRgb888();
+}
+
+bool image_io_read_rgb888(const char* filename, int* width, int* height,
+                          uint8_t** image) {
+  auto reader = ImageIoReader::Create(filename);
+  if (!reader)
+    return false;
+  if (!reader->ReadRgb888())
+    return false;
+  *width = reader->width();
+  *height = reader->height();
+  *image = reader->ReleaseImage();
+  return true;
+}
+
+void image_io_release_buffer(uint8_t* image) { delete[] image; }
+
+}  // extern "C"
diff --git a/libs/vr/libimageio/image_io_png.cpp b/libs/vr/libimageio/image_io_png.cpp
new file mode 100644
index 0000000..e0a118b
--- /dev/null
+++ b/libs/vr/libimageio/image_io_png.cpp
@@ -0,0 +1,87 @@
+#define LOG_TAG "ImageIo"
+
+#include <private/dvr/image_io_png.h>
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <private/dvr/image_io_logging.h>
+
+#include "png.h"
+
+namespace {
+
+void WriteChunkCallback(png_structp out_ptr, png_bytep chunk_ptr,
+                        png_size_t chunk_size) {
+  auto* writer = static_cast<ImageIoPngWriter*>(png_get_io_ptr(out_ptr));
+  const char* chunk = reinterpret_cast<const char*>(chunk_ptr);
+  writer->WriteChunk(chunk, chunk_size);
+}
+
+}  // namespace
+
+ImageIoPngWriter::ImageIoPngWriter(const char* filename, int width, int height,
+                                   const uint8_t* image)
+    : ImageIoWriter(filename, width, height, image),
+      out_(filename_),
+      write_failed_(false) {}
+
+bool ImageIoPngWriter::WriteChunk(const char* chunk, int chunk_size) {
+  out_.write(chunk, chunk_size);
+  if (!out_) {
+    if (write_failed_) {
+      // Error was already logged once.
+      return false;
+    }
+
+    ALOGE("Failed to write .png image to %s.", filename_.c_str());
+    write_failed_ = true;
+    return false;
+  }
+  return true;
+}
+
+// Writes RGB888 image to png file.
+// Refactored from Chromium:
+// WebKit/Source/platform/image-encoders/skia/PNGImageEncoder.cpp
+bool ImageIoPngWriter::WriteRgb888() {
+  if (width_ <= 0 || height_ <= 0) {
+    ALOGE("Invalid width or height.");
+    return false;
+  }
+
+  if (!out_) {
+    ALOGE("Failed to open output file %s.", filename_.c_str());
+    return false;
+  }
+
+  png_struct* png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+  png_info* info = png_create_info_struct(png);
+  if (!png || !info || setjmp(png_jmpbuf(png))) {
+    png_destroy_write_struct(png ? &png : 0, info ? &info : 0);
+    return false;
+  }
+
+  png_set_compression_level(png, 3);
+  png_set_filter(png, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
+
+  png_set_write_fn(png, this, WriteChunkCallback, 0);
+  png_set_IHDR(png, info, width_, height_, 8, PNG_COLOR_TYPE_RGB, 0, 0, 0);
+  png_write_info(png, info);
+
+  unsigned char* pixels =
+      reinterpret_cast<unsigned char*>(const_cast<uint8_t*>(image_));
+  const size_t stride = width_ * 3;
+  for (int y = 0; y < height_; ++y) {
+    png_write_row(png, pixels);
+    if (write_failed_)
+      return false;
+    pixels += stride;
+  }
+
+  png_write_end(png, info);
+  png_destroy_write_struct(&png, &info);
+
+  return !write_failed_;
+}
diff --git a/libs/vr/libimageio/image_io_ppm.cpp b/libs/vr/libimageio/image_io_ppm.cpp
new file mode 100644
index 0000000..2411888
--- /dev/null
+++ b/libs/vr/libimageio/image_io_ppm.cpp
@@ -0,0 +1,93 @@
+#define LOG_TAG "ImageIo"
+
+#include <private/dvr/image_io_ppm.h>
+
+#include <cwctype>
+#include <fstream>
+#include <string>
+
+#include <private/dvr/image_io_logging.h>
+
+bool ImageIoPpmWriter::WriteRgb888() {
+  std::ofstream out(filename_);
+  if (!out) {
+    ALOGE("Failed to open output file %s.", filename_.c_str());
+    return false;
+  }
+
+  // Write a PPM header. See http://netpbm.sourceforge.net/doc/ppm.html for
+  // the format specification.
+  constexpr int maximum_intensity = 255;
+  out << "P6\n"
+      << width_ << "\n"
+      << height_ << "\n"
+      << maximum_intensity << "\n";
+
+  // Write out the image itself.
+  out.write(reinterpret_cast<const char*>(image_), 3 * width_ * height_);
+
+  if (!out) {
+    ALOGE("Failed to write .ppm image to %s.", filename_.c_str());
+    return false;
+  }
+  return true;
+}
+
+bool ImageIoPpmReader::ReadRgb888() {
+  std::ifstream in(filename_);
+  if (!in) {
+    ALOGE("Failed to open input file %s.", filename_.c_str());
+    return false;
+  }
+
+  // Read PPM header. See http://netpbm.sourceforge.net/doc/ppm.html for
+  // the format specification.
+  char magic_number[2];
+  in.read(magic_number, 2);
+  if (magic_number[0] != 'P' || magic_number[1] != '6') {
+    ALOGE("Failed to read PPM, not a P6 file %s.", filename_.c_str());
+    return false;
+  }
+
+  int maximum_intensity = 0;
+
+  in >> width_;
+  in >> height_;
+  in >> maximum_intensity;
+
+  char delimiter;
+  in.read(&delimiter, 1);
+
+  if (!iswspace(delimiter) || width_ <= 0 || height_ <= 0 ||
+      maximum_intensity <= 0) {
+    ALOGE("Failed to parse PPM header for %s.", filename_.c_str());
+    return false;
+  }
+
+  if (maximum_intensity != 255) {
+    ALOGE("Failed to read PPM, only 8-bit depth supported %s.",
+          filename_.c_str());
+    return false;
+  }
+
+  // Read RGB data.
+  const int data_begin = in.tellg();
+  in.seekg(0, in.end);
+  const int data_end = in.tellg();
+  in.seekg(data_begin, in.beg);
+
+  const int data_size = data_end - data_begin;
+  if (data_size != 3 * width_ * height_) {
+    ALOGE("Failed to read PPM, unexpected data size %s.", filename_.c_str());
+    return false;
+  }
+
+  image_.reset(new uint8_t[data_size]);
+  char* data = reinterpret_cast<char*>(image_.get());
+
+  const auto it_data_begin = std::istreambuf_iterator<char>(in);
+  const auto it_data_end = std::istreambuf_iterator<char>();
+  std::copy(it_data_begin, it_data_end, data);
+
+  return true;
+}
diff --git a/libs/vr/libimageio/include/CPPLINT.cfg b/libs/vr/libimageio/include/CPPLINT.cfg
new file mode 100644
index 0000000..2f8a3c0
--- /dev/null
+++ b/libs/vr/libimageio/include/CPPLINT.cfg
@@ -0,0 +1 @@
+filter=-build/header_guard
diff --git a/libs/vr/libimageio/include/private/dvr/image_io.h b/libs/vr/libimageio/include/private/dvr/image_io.h
new file mode 100644
index 0000000..5cb115d
--- /dev/null
+++ b/libs/vr/libimageio/include/private/dvr/image_io.h
@@ -0,0 +1,32 @@
+#ifndef DVR_IMAGE_IO_H_
+#define DVR_IMAGE_IO_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// Supported filetypes.
+#define DVR_IMAGE_IO_SUPPORTED_WRITE "png, ppm"
+#define DVR_IMAGE_IO_SUPPORTED_READ "ppm"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Writes an RGB888 image to file. Intended file type is autodetected
+// based on the extension. Currently supported formats: PNG, PPM.
+bool image_io_write_rgb888(const char* filename, int width, int height,
+                           const uint8_t* image);
+
+// Reads an RGB888 image from file. Image buffer needs to be released with
+// image_io_release_image. Currently supported formats: PPM.
+bool image_io_read_rgb888(const char* filename, int* width, int* height,
+                          uint8_t** image);
+
+// Releases image buffer allocated within the library.
+void image_io_release_buffer(uint8_t* image);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // DVR_IMAGE_IO_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_base.h b/libs/vr/libimageio/include/private/dvr/image_io_base.h
new file mode 100644
index 0000000..009cad4
--- /dev/null
+++ b/libs/vr/libimageio/include/private/dvr/image_io_base.h
@@ -0,0 +1,56 @@
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_BASE_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_BASE_H_
+
+#include <memory>
+#include <string>
+
+class ImageIoReader {
+ public:
+  virtual ~ImageIoReader() {}
+
+  static std::unique_ptr<ImageIoReader> Create(const char* filename);
+
+  virtual bool ReadRgb888() = 0;
+
+  int width() const { return width_; }
+
+  int height() const { return height_; }
+
+  uint8_t* ReleaseImage() { return image_.release(); }
+
+ protected:
+  int width_;
+  int height_;
+  std::unique_ptr<uint8_t[]> image_;
+  const std::string filename_;
+
+  explicit ImageIoReader(const char* filename)
+      : width_(0), height_(0), filename_(filename) {}
+
+  ImageIoReader() = delete;
+};
+
+class ImageIoWriter {
+ public:
+  virtual ~ImageIoWriter() {}
+
+  static std::unique_ptr<ImageIoWriter> Create(const char* filename, int width,
+                                               int height,
+                                               const uint8_t* image);
+
+  virtual bool WriteRgb888() = 0;
+
+ protected:
+  const int width_;
+  const int height_;
+  const uint8_t* image_;
+  const std::string filename_;
+
+  ImageIoWriter(const char* filename, int width, int height,
+                const uint8_t* image)
+      : width_(width), height_(height), image_(image), filename_(filename) {}
+
+  ImageIoWriter() = delete;
+};
+
+#endif  // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_BASE_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_logging.h b/libs/vr/libimageio/include/private/dvr/image_io_logging.h
new file mode 100644
index 0000000..3c0f2a5
--- /dev/null
+++ b/libs/vr/libimageio/include/private/dvr/image_io_logging.h
@@ -0,0 +1,39 @@
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_LOGGING_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_LOGGING_H_
+
+// This header acts as cutils/log.h if LOG_TO_STDERR is not defined.
+// If LOG_TO_STDERR is defined, then android logging macros (such as ALOGE)
+// would log to stderr. This is useful if the code is also being used/tested on
+// a desktop.
+
+#ifdef LOG_TO_STDERR
+#include <stdarg.h>
+#include <cstdio>
+
+#ifndef LOG_TAG
+#define LOG_TAG " "
+#endif  // LOG_TAG
+
+inline void LogToStderr(const char* severity, const char* fmt, ...) {
+  fprintf(stderr, "%s %s: ", LOG_TAG, severity);
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+  fprintf(stderr, "\n");
+  fflush(stderr);
+}
+
+#define ALOGE(fmt, ...) LogToStderr("ERROR", fmt, ##__VA_ARGS__)
+
+#define ALOGW(fmt, ...) LogToStderr("WARNING", fmt, ##__VA_ARGS__)
+
+#define ALOGI(fmt, ...) LogToStderr("INFO", fmt, ##__VA_ARGS__)
+
+#define ALOGV(fmt, ...) LogToStderr("VERBOSE", fmt, ##__VA_ARGS__)
+
+#else  // LOG_TO_STDERR
+#include <cutils/log.h>
+#endif  // LOG_TO_STDERR
+
+#endif  // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_LOGGING_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_png.h b/libs/vr/libimageio/include/private/dvr/image_io_png.h
new file mode 100644
index 0000000..e3b19db
--- /dev/null
+++ b/libs/vr/libimageio/include/private/dvr/image_io_png.h
@@ -0,0 +1,24 @@
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PNG_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PNG_H_
+
+#include <fstream>
+
+#include <private/dvr/image_io_base.h>
+
+class ImageIoPngWriter : public ImageIoWriter {
+ public:
+  bool WriteRgb888() override;
+
+  bool WriteChunk(const char* chunk, int chunk_size);
+
+ private:
+  ImageIoPngWriter(const char* filename, int width, int height,
+                   const uint8_t* image);
+
+  std::ofstream out_;
+  bool write_failed_;
+
+  friend class ImageIoWriter;
+};
+
+#endif  // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PNG_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_ppm.h b/libs/vr/libimageio/include/private/dvr/image_io_ppm.h
new file mode 100644
index 0000000..00264bd
--- /dev/null
+++ b/libs/vr/libimageio/include/private/dvr/image_io_ppm.h
@@ -0,0 +1,28 @@
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PPM_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PPM_H_
+
+#include <private/dvr/image_io_base.h>
+
+class ImageIoPpmReader : public ImageIoReader {
+ public:
+  bool ReadRgb888() override;
+
+ private:
+  explicit ImageIoPpmReader(const char* filename) : ImageIoReader(filename) {}
+
+  friend class ImageIoReader;
+};
+
+class ImageIoPpmWriter : public ImageIoWriter {
+ public:
+  bool WriteRgb888() override;
+
+ private:
+  ImageIoPpmWriter(const char* filename, int width, int height,
+                   const uint8_t* image)
+      : ImageIoWriter(filename, width, height, image) {}
+
+  friend class ImageIoWriter;
+};
+
+#endif  // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PPM_H_