Merge "libui: log an error on allocation failure" into oc-dev
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index ae4c797..ff838ce 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -313,8 +313,7 @@
                                         + 1   // filter
                                         + 1   // volume
                                         + 1   // libs
-                                        + 1   // seinfo
-                                        + 1;  // null
+                                        + 1;  // seinfo
             if (argc == kV2ArgCount) {
                 return ReadArgumentsV2(argc, argv, false);
             } else {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 1f56a47..45bb1d0 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -65,11 +65,7 @@
 static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
 {
     char *sctx = NULL;
-#ifdef VENDORSERVICEMANAGER
-    const char *class = "vndservice_manager";
-#else
     const char *class = "service_manager";
-#endif
     bool allowed;
     struct audit_data ad;
 
diff --git a/libs/vr/libdisplay/include/private/dvr/late_latch.h b/libs/vr/libdisplay/include/private/dvr/late_latch.h
index d0eff51..b7c5e4f 100644
--- a/libs/vr/libdisplay/include/private/dvr/late_latch.h
+++ b/libs/vr/libdisplay/include/private/dvr/late_latch.h
@@ -178,6 +178,9 @@
   LateLatchOutput* eds_late_latch_output_;
 
   DvrPose* pose_client_;
+
+  pdx::LocalHandle surface_metadata_fd_;
+  pdx::LocalHandle pose_buffer_fd_;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libdisplay/late_latch.cpp b/libs/vr/libdisplay/late_latch.cpp
index b1a1589..e67f009 100644
--- a/libs/vr/libdisplay/late_latch.cpp
+++ b/libs/vr/libdisplay/late_latch.cpp
@@ -252,7 +252,8 @@
                      LocalHandle&& surface_metadata_fd)
     : is_app_late_latch_(is_app_late_latch),
       app_late_latch_output_(NULL),
-      eds_late_latch_output_(NULL) {
+      eds_late_latch_output_(NULL),
+      surface_metadata_fd_(std::move(surface_metadata_fd)) {
   CHECK_GL();
   glGenBuffers(1, &input_buffer_id_);
   glBindBuffer(GL_SHADER_STORAGE_BUFFER, input_buffer_id_);
@@ -264,12 +265,11 @@
                GL_DYNAMIC_COPY);
   CHECK_GL();
 
-  LocalHandle pose_buffer_fd;
   pose_client_ = dvrPoseCreate();
   if (!pose_client_) {
     ALOGE("LateLatch Error: failed to create pose client");
   } else {
-    int ret = privateDvrPoseGetRingBufferFd(pose_client_, &pose_buffer_fd);
+    int ret = privateDvrPoseGetRingBufferFd(pose_client_, &pose_buffer_fd_);
     if (ret < 0) {
       ALOGE("LateLatch Error: failed to get pose ring buffer");
     }
@@ -280,20 +280,20 @@
   if (!glBindSharedBufferQCOM) {
     ALOGE("Error: Missing gralloc buffer extension, no pose data");
   } else {
-    if (pose_buffer_fd) {
+    if (pose_buffer_fd_) {
       glBindBuffer(GL_SHADER_STORAGE_BUFFER, pose_buffer_object_);
       glBindSharedBufferQCOM(GL_SHADER_STORAGE_BUFFER,
                              kPoseAsyncBufferTotalCount * sizeof(DvrPoseAsync),
-                             pose_buffer_fd.Release());
+                             pose_buffer_fd_.Get());
     }
     CHECK_GL();
   }
 
   glBindBuffer(GL_SHADER_STORAGE_BUFFER, metadata_buffer_id_);
-  if (surface_metadata_fd && glBindSharedBufferQCOM) {
+  if (surface_metadata_fd_ && glBindSharedBufferQCOM) {
     glBindSharedBufferQCOM(GL_SHADER_STORAGE_BUFFER,
                            sizeof(DisplaySurfaceMetadata),
-                           surface_metadata_fd.Release());
+                           surface_metadata_fd_.Get());
   } else {
     // Fall back on internal metadata buffer when none provided, for example
     // when distortion is done in the application process.
diff --git a/libs/vr/libeds/Android.bp b/libs/vr/libeds/Android.bp
index 85e43cc..a149853 100644
--- a/libs/vr/libeds/Android.bp
+++ b/libs/vr/libeds/Android.bp
@@ -19,7 +19,6 @@
     "display_metrics.cpp",
     "distortion_renderer.cpp",
     "device_metrics.cpp",
-    "lookup_radial_distortion.cpp",
     "polynomial_radial_distortion.cpp",
 ]
 
diff --git a/libs/vr/libeds/device_metrics.cpp b/libs/vr/libeds/device_metrics.cpp
index 50c3e54..68ee186 100644
--- a/libs/vr/libeds/device_metrics.cpp
+++ b/libs/vr/libeds/device_metrics.cpp
@@ -3,14 +3,12 @@
 #include <cutils/properties.h>
 #include <private/dvr/head_mount_metrics.h>
 #include <private/dvr/identity_distortion.h>
-#include <private/dvr/lookup_radial_distortion.h>
 #include <private/dvr/polynomial_radial_distortion.h>
 #include <private/dvr/types.h>
 #include "include/private/dvr/display_metrics.h"
 
 namespace {
 
-static constexpr char kRGBPolynomialOffset[] = "persist.dvr.rgb_poly_offset";
 static constexpr char kRPolynomial[] = "persist.dvr.r_poly";
 static constexpr char kGPolynomial[] = "persist.dvr.g_poly";
 static constexpr char kBPolynomial[] = "persist.dvr.b_poly";
@@ -68,7 +66,9 @@
 
 float GetDisplayGap() { return GetProperty(kDisplayGap, 0.0f); }
 
-float GetVEyeToDisplay() { return GetProperty(kVEyeToDisplay, 0.035f); }
+float GetTrayToLensDistance() { return 0.035f; }
+
+float GetVEyeToDisplay() { return GetProperty(kVEyeToDisplay, 0.042f); }
 
 android::dvr::vec2 GetDisplaySize() {
   static const std::vector<float> default_size = {0.0742177f, 0.131943f};
@@ -110,33 +110,23 @@
 HeadMountMetrics CreateHeadMountMetrics(const FieldOfView& l_fov,
                                         const FieldOfView& r_fov) {
   static const std::vector<float> default_r = {
-      -4.08519004f,  34.70282075f, -67.37781249f, 56.97304235f,
-      -23.35768685f, 4.7199597f,   0.63198082f};
+      0.00103f, 2.63917f, -7.14427f, 8.98036f, -4.10586f, 0.83705f, 0.00130f};
   static const std::vector<float> default_g = {
-      4.43078318f, 3.47806617f, -20.58017398f, 20.85880414f,
-      -8.4046504f, 1.61284685f, 0.8881761f};
+      0.08944f, 2.26005f, -6.30924f, 7.94561f, -3.22788f, 0.45577f, 0.07300f};
   static const std::vector<float> default_b = {
-      12.04141265f, -21.98112491f, 14.06758389f, -3.15245629f,
-      0.36549102f,  0.05252705f,   0.99844279f};
-  static const std::vector<float> default_offsets = {
-      0.20971645238f, 0.15189450000f, 1.00096958278f};
-
-  std::vector<float> poly_offsets =
-      GetProperty(kRGBPolynomialOffset, default_offsets);
+      0.16364f, 1.94083f, -5.55033f, 6.89578f, -2.19053f, -0.04050f, 0.17380f};
   std::vector<float> poly_r = GetProperty(kRPolynomial, default_r);
   std::vector<float> poly_g = GetProperty(kGPolynomial, default_g);
   std::vector<float> poly_b = GetProperty(kBPolynomial, default_b);
-  if (poly_offsets.size() != 3)
-    poly_offsets = default_offsets;
 
   std::shared_ptr<ColorChannelDistortion> distortion_r(
-      new PolynomialRadialDistortion(poly_offsets[0], poly_r));
+      new PolynomialRadialDistortion(poly_r));
   std::shared_ptr<ColorChannelDistortion> distortion_g(
-      new PolynomialRadialDistortion(poly_offsets[1], poly_g));
+      new PolynomialRadialDistortion(poly_g));
   std::shared_ptr<ColorChannelDistortion> distortion_b(
-      new PolynomialRadialDistortion(poly_offsets[2], poly_b));
+      new PolynomialRadialDistortion(poly_b));
 
-  return HeadMountMetrics(GetInterLensDistance(), GetVEyeToDisplay(),
+  return HeadMountMetrics(GetInterLensDistance(), GetTrayToLensDistance(),
                           GetVEyeToDisplay(), kDefaultVerticalAlignment, l_fov,
                           r_fov, distortion_r, distortion_g, distortion_b,
                           HeadMountMetrics::EyeOrientation::kCCW0Degrees,
diff --git a/libs/vr/libeds/include/private/dvr/lookup_radial_distortion.h b/libs/vr/libeds/include/private/dvr/lookup_radial_distortion.h
deleted file mode 100644
index 56fc5db..0000000
--- a/libs/vr/libeds/include/private/dvr/lookup_radial_distortion.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef ANDROID_DVR_LOOKUP_RADIAL_DISTORTION_H_
-#define ANDROID_DVR_LOOKUP_RADIAL_DISTORTION_H_
-
-#include <vector>
-
-#include <private/dvr/color_channel_distortion.h>
-
-namespace android {
-namespace dvr {
-
-// LookupRadialDistortion implements a radial distortion based using using a
-// vector of tan(angle) -> multipliers.  This can use measured data directly.
-class LookupRadialDistortion : public ColorChannelDistortion {
- public:
-  // lookup.x = tan(angle), lookup.y = distance from center multiplier.
-  explicit LookupRadialDistortion(const vec2* lookup, size_t count);
-
-  vec2 Distort(vec2 p) const override;
-  vec2 DistortInverse(vec2 p) const override;
-
- private:
-  float DistortionFactor(float r) const;
-  float DistortRadius(float r) const;
-
-  std::vector<vec2> lookup_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_LOOKUP_RADIAL_DISTORTION_H_
diff --git a/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h b/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h
index c1f1ce9..8f080aa 100644
--- a/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h
+++ b/libs/vr/libeds/include/private/dvr/polynomial_radial_distortion.h
@@ -28,8 +28,7 @@
   // in the distortion equation: coefficients[0] is K1, coefficients[1] is K2,
   // etc.  Thus the polynomial used for distortion has degree
   // (2 * coefficients.size()).
-  explicit PolynomialRadialDistortion(float polynomial_offset,
-                                      const std::vector<float>& coefficients);
+  explicit PolynomialRadialDistortion(const std::vector<float>& coefficients);
 
   // Given a radius (measuring distance from the optical axis of the lens),
   // returns the distortion factor for that radius.
@@ -52,10 +51,6 @@
   const std::vector<float>& GetCoefficients() const;
 
  private:
-  // This is makes the polynomial work nicer with a specific lens that doesn't
-  // fit nicely to a lower order polynomial.  It's basically piecewise
-  // line->poly.
-  float polynomial_offset_;
   std::vector<float> coefficients_;
 };
 
diff --git a/libs/vr/libeds/lookup_radial_distortion.cpp b/libs/vr/libeds/lookup_radial_distortion.cpp
deleted file mode 100644
index 2cee863..0000000
--- a/libs/vr/libeds/lookup_radial_distortion.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "include/private/dvr/lookup_radial_distortion.h"
-
-namespace android {
-namespace dvr {
-
-LookupRadialDistortion::LookupRadialDistortion(const vec2* lookup, size_t count)
-    : lookup_(lookup, lookup + count) {}
-
-float LookupRadialDistortion::DistortionFactor(float r) const {
-  for (size_t i = 1; i < lookup_.size(); ++i) {
-    if (lookup_[i].x() > r) {
-      float t =
-          (r - lookup_[i - 1].x()) / (lookup_[i].x() - lookup_[i - 1].x());
-      return lookup_[i - 1].y() + t * (lookup_[i].y() - lookup_[i - 1].y());
-    }
-  }
-  return lookup_.back().y();
-}
-
-float LookupRadialDistortion::DistortRadius(float r) const {
-  return r * DistortionFactor(r);
-}
-
-vec2 LookupRadialDistortion::Distort(vec2 p) const {
-  return p * DistortionFactor(p.norm());
-}
-
-vec2 LookupRadialDistortion::DistortInverse(vec2 p) const {
-  // Secant method.
-  const float radius = p.norm();
-  float r0 = radius / 0.9f;
-  float r1 = radius * 0.9f;
-  float r2;
-  float dr0 = radius - DistortRadius(r0);
-  float dr1;
-  while (fabsf(r1 - r0) > 0.0001f /** 0.1mm */) {
-    dr1 = radius - DistortRadius(r1);
-    r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
-    r0 = r1;
-    r1 = r2;
-    dr0 = dr1;
-  }
-  return (r1 / radius) * p;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libeds/polynomial_radial_distortion.cpp b/libs/vr/libeds/polynomial_radial_distortion.cpp
index a0c6ea3..fa01bb4 100644
--- a/libs/vr/libeds/polynomial_radial_distortion.cpp
+++ b/libs/vr/libeds/polynomial_radial_distortion.cpp
@@ -4,13 +4,10 @@
 namespace dvr {
 
 PolynomialRadialDistortion::PolynomialRadialDistortion(
-    float polynomial_offset, const std::vector<float>& coefficients)
-    : polynomial_offset_(polynomial_offset), coefficients_(coefficients) {}
+    const std::vector<float>& coefficients)
+    : coefficients_(coefficients) {}
 
 float PolynomialRadialDistortion::DistortionFactor(float r_squared) const {
-  if (r_squared < polynomial_offset_)
-    return 1.0f;
-
   float r_factor = 1.0f;
   float distortion_factor = 1.0f;
 
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index f2bcc0c..cfc2022 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -35,6 +35,7 @@
         "-Werror",
     ],
     srcs: [
+        "client_channel_tests.cpp",
         "ipc_helper_tests.cpp",
         "remote_method_tests.cpp",
         "service_framework_tests.cpp",
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 924335f..9d91617 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -156,6 +156,7 @@
 
 Status<void> ClientChannel::SendImpulse(int opcode, const void* buffer,
                                         size_t length) {
+  std::unique_lock<std::mutex> lock(socket_mutex_);
   Status<void> status;
   android::pdx::uds::RequestHeader<BorrowedHandle> request;
   if (length > request.impulse_payload.size() ||
@@ -174,6 +175,7 @@
                                           size_t send_count,
                                           const iovec* receive_vector,
                                           size_t receive_count) {
+  std::unique_lock<std::mutex> lock(socket_mutex_);
   Status<int> result;
   if ((send_vector == nullptr && send_count != 0) ||
       (receive_vector == nullptr && receive_count != 0)) {
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 9202cd5..850c6d3 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -39,32 +39,42 @@
 ClientChannelFactory::ClientChannelFactory(const std::string& endpoint_path)
     : endpoint_path_{GetEndpointPath(endpoint_path)} {}
 
+ClientChannelFactory::ClientChannelFactory(LocalHandle socket)
+    : socket_{std::move(socket)} {}
+
 std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
     const std::string& endpoint_path) {
   return std::unique_ptr<pdx::ClientChannelFactory>{
       new ClientChannelFactory{endpoint_path}};
 }
 
+std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
+    LocalHandle socket) {
+  return std::unique_ptr<pdx::ClientChannelFactory>{
+      new ClientChannelFactory{std::move(socket)}};
+}
+
 Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
     int64_t timeout_ms) const {
   Status<void> status;
 
-  LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
-  if (!socket_fd) {
+  bool connected = socket_.IsValid();
+  if (!connected) {
+    socket_.Reset(socket(AF_UNIX, SOCK_STREAM, 0));
+    LOG_ALWAYS_FATAL_IF(
+        endpoint_path_.empty(),
+        "ClientChannelFactory::Connect: unspecified socket path");
+  }
+
+  if (!socket_) {
     ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
     return ErrorStatus(errno);
   }
 
-  sockaddr_un remote;
-  remote.sun_family = AF_UNIX;
-  strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
-  remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
-
   bool use_timeout = (timeout_ms >= 0);
   auto now = steady_clock::now();
   auto time_end = now + std::chrono::milliseconds{timeout_ms};
 
-  bool connected = false;
   int max_eaccess = 5;  // Max number of times to retry when EACCES returned.
   while (!connected) {
     int64_t timeout = -1;
@@ -74,6 +84,10 @@
       if (timeout < 0)
         return ErrorStatus(ETIMEDOUT);
     }
+    sockaddr_un remote;
+    remote.sun_family = AF_UNIX;
+    strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
+    remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
     ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
     status = WaitForEndpoint(endpoint_path_, timeout);
     if (!status)
@@ -81,7 +95,7 @@
 
     ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
     int ret = RETRY_EINTR(connect(
-        socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
+        socket_.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
     if (ret == -1) {
       ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
             strerror(errno));
@@ -107,20 +121,20 @@
       }
     } else {
       connected = true;
+      ALOGD("ClientChannelFactory: Connected successfully to %s...",
+            remote.sun_path);
     }
     if (use_timeout)
       now = steady_clock::now();
   }  // while (!connected)
 
-  ALOGD("ClientChannelFactory: Connected successfully to %s...",
-        remote.sun_path);
   RequestHeader<BorrowedHandle> request;
   InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
-  status = SendData(socket_fd.Borrow(), request);
+  status = SendData(socket_.Borrow(), request);
   if (!status)
     return ErrorStatus(status.error());
   ResponseHeader<LocalHandle> response;
-  status = ReceiveData(socket_fd.Borrow(), &response);
+  status = ReceiveData(socket_.Borrow(), &response);
   if (!status)
     return ErrorStatus(status.error());
   int ref = response.ret_code;
@@ -129,7 +143,7 @@
 
   LocalHandle event_fd = std::move(response.file_descriptors[ref]);
   return ClientChannel::Create(ChannelManager::Get().CreateHandle(
-      std::move(socket_fd), std::move(event_fd)));
+      std::move(socket_), std::move(event_fd)));
 }
 
 }  // namespace uds
diff --git a/libs/vr/libpdx_uds/client_channel_tests.cpp b/libs/vr/libpdx_uds/client_channel_tests.cpp
new file mode 100644
index 0000000..7c3c68a
--- /dev/null
+++ b/libs/vr/libpdx_uds/client_channel_tests.cpp
@@ -0,0 +1,162 @@
+#include <uds/client_channel.h>
+
+#include <sys/socket.h>
+
+#include <algorithm>
+#include <limits>
+#include <random>
+#include <thread>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <pdx/client.h>
+#include <pdx/rpc/remote_method.h>
+#include <pdx/service.h>
+
+#include <uds/client_channel_factory.h>
+#include <uds/service_endpoint.h>
+
+using testing::Return;
+using testing::_;
+
+using android::pdx::ClientBase;
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Message;
+using android::pdx::ServiceBase;
+using android::pdx::ServiceDispatcher;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+using android::pdx::uds::ClientChannel;
+using android::pdx::uds::ClientChannelFactory;
+using android::pdx::uds::Endpoint;
+
+namespace {
+
+struct TestProtocol {
+  using DataType = int8_t;
+  enum {
+    kOpSum = 0,
+  };
+  PDX_REMOTE_METHOD(Sum, kOpSum, int64_t(const std::vector<DataType>&));
+};
+
+class TestService : public ServiceBase<TestService> {
+ public:
+  TestService(std::unique_ptr<Endpoint> endpoint)
+      : ServiceBase{"TestService", std::move(endpoint)} {}
+
+  Status<void> HandleMessage(Message& message) override {
+    switch (message.GetOp()) {
+      case TestProtocol::kOpSum:
+        DispatchRemoteMethod<TestProtocol::Sum>(*this, &TestService::OnSum,
+                                                message);
+        return {};
+
+      default:
+        return Service::HandleMessage(message);
+    }
+  }
+
+  int64_t OnSum(Message& /*message*/,
+                const std::vector<TestProtocol::DataType>& data) {
+    return std::accumulate(data.begin(), data.end(), int64_t{0});
+  }
+};
+
+class TestClient : public ClientBase<TestClient> {
+ public:
+  using ClientBase::ClientBase;
+
+  int64_t Sum(const std::vector<TestProtocol::DataType>& data) {
+    auto status = InvokeRemoteMethod<TestProtocol::Sum>(data);
+    return status ? status.get() : -1;
+  }
+};
+
+class TestServiceRunner {
+ public:
+  TestServiceRunner(LocalHandle channel_socket) {
+    auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{});
+    endpoint->RegisterNewChannelForTests(std::move(channel_socket));
+    service_ = TestService::Create(std::move(endpoint));
+    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_->AddService(service_);
+    dispatch_thread_ = std::thread(
+        std::bind(&ServiceDispatcher::EnterDispatchLoop, dispatcher_.get()));
+  }
+
+  ~TestServiceRunner() {
+    dispatcher_->SetCanceled(true);
+    dispatch_thread_.join();
+    dispatcher_->RemoveService(service_);
+  }
+
+ private:
+  std::shared_ptr<TestService> service_;
+  std::unique_ptr<ServiceDispatcher> dispatcher_;
+  std::thread dispatch_thread_;
+};
+
+class ClientChannelTest : public testing::Test {
+ public:
+  void SetUp() override {
+    int channel_sockets[2] = {};
+    ASSERT_EQ(
+        0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_sockets));
+    LocalHandle service_channel{channel_sockets[0]};
+    LocalHandle client_channel{channel_sockets[1]};
+
+    service_runner_.reset(new TestServiceRunner{std::move(service_channel)});
+    auto factory = ClientChannelFactory::Create(std::move(client_channel));
+    auto status = factory->Connect(android::pdx::Client::kInfiniteTimeout);
+    ASSERT_TRUE(status);
+    client_ = TestClient::Create(status.take());
+  }
+
+  void TearDown() override {
+    service_runner_.reset();
+    client_.reset();
+  }
+
+ protected:
+  std::unique_ptr<TestServiceRunner> service_runner_;
+  std::shared_ptr<TestClient> client_;
+};
+
+TEST_F(ClientChannelTest, MultithreadedClient) {
+  constexpr int kNumTestThreads = 8;
+  constexpr size_t kDataSize = 1000;  // Try to keep RPC buffer size below 4K.
+
+  std::random_device rd;
+  std::mt19937 gen{rd()};
+  std::uniform_int_distribution<TestProtocol::DataType> dist{
+      std::numeric_limits<TestProtocol::DataType>::min(),
+      std::numeric_limits<TestProtocol::DataType>::max()};
+
+  auto worker = [](std::shared_ptr<TestClient> client,
+                   std::vector<TestProtocol::DataType> data) {
+    constexpr int kMaxIterations = 500;
+    int64_t expected = std::accumulate(data.begin(), data.end(), int64_t{0});
+    for (int i = 0; i < kMaxIterations; i++) {
+      ASSERT_EQ(expected, client->Sum(data));
+    }
+  };
+
+  // Start client threads.
+  std::vector<TestProtocol::DataType> data;
+  data.resize(kDataSize);
+  std::vector<std::thread> threads;
+  for (int i = 0; i < kNumTestThreads; i++) {
+    std::generate(data.begin(), data.end(),
+                  [&dist, &gen]() { return dist(gen); });
+    threads.emplace_back(worker, client_, data);
+  }
+
+  // Wait for threads to finish.
+  for (auto& thread : threads)
+    thread.join();
+}
+
+}  // namespace
diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp
index b675894..d75ce86 100644
--- a/libs/vr/libpdx_uds/ipc_helper.cpp
+++ b/libs/vr/libpdx_uds/ipc_helper.cpp
@@ -275,6 +275,7 @@
     return ret;
 
   if (preamble.magic != kMagicPreamble) {
+    ALOGE("ReceivePayload::Receive: Message header is invalid");
     ret.SetError(EIO);
     return ret;
   }
@@ -319,8 +320,10 @@
     cmsg = CMSG_NXTHDR(&msg, cmsg);
   }
 
-  if (cred && !cred_available)
+  if (cred && !cred_available) {
+    ALOGE("ReceivePayload::Receive: Failed to obtain message credentials");
     ret.SetError(EIO);
+  }
 
   return ret;
 }
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h
index 45f6473..8f607f5 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel.h
@@ -3,6 +3,8 @@
 
 #include <pdx/client_channel.h>
 
+#include <mutex>
+
 #include <uds/channel_event_set.h>
 #include <uds/channel_manager.h>
 #include <uds/service_endpoint.h>
@@ -73,6 +75,7 @@
 
   LocalChannelHandle channel_handle_;
   ChannelManager::ChannelData* channel_data_;
+  std::mutex socket_mutex_;
 };
 
 }  // namespace uds
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel_factory.h b/libs/vr/libpdx_uds/private/uds/client_channel_factory.h
index 6f80d31..c43c5c7 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel_factory.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel_factory.h
@@ -13,6 +13,7 @@
  public:
   static std::unique_ptr<pdx::ClientChannelFactory> Create(
       const std::string& endpoint_path);
+  static std::unique_ptr<pdx::ClientChannelFactory> Create(LocalHandle socket);
 
   Status<std::unique_ptr<pdx::ClientChannel>> Connect(
       int64_t timeout_ms) const override;
@@ -22,7 +23,9 @@
 
  private:
   explicit ClientChannelFactory(const std::string& endpoint_path);
+  explicit ClientChannelFactory(LocalHandle socket);
 
+  mutable LocalHandle socket_;
   std::string endpoint_path_;
 };
 
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index f747abc..eb87827 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -97,6 +97,14 @@
   static std::unique_ptr<Endpoint> CreateAndBindSocket(
       const std::string& endpoint_path, bool blocking = kDefaultBlocking);
 
+  // Helper method to create an endpoint from an existing socket FD.
+  // Mostly helpful for tests.
+  static std::unique_ptr<Endpoint> CreateFromSocketFd(LocalHandle socket_fd);
+
+  // Test helper method to register a new channel identified by |channel_fd|
+  // socket file descriptor.
+  Status<void> RegisterNewChannelForTests(LocalHandle channel_fd);
+
   int epoll_fd() const { return epoll_fd_.Get(); }
 
  private:
@@ -109,6 +117,9 @@
   // This class must be instantiated using Create() static methods above.
   Endpoint(const std::string& endpoint_path, bool blocking,
            bool use_init_socket_fd = true);
+  Endpoint(LocalHandle socket_fd);
+
+  void Init(LocalHandle socket_fd);
 
   Endpoint(const Endpoint&) = delete;
   void operator=(const Endpoint&) = delete;
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 65fd59f..6c92259 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -161,9 +161,16 @@
         bind(fd.Get(), reinterpret_cast<sockaddr*>(&local), sizeof(local));
     CHECK_EQ(ret, 0) << "Endpoint::Endpoint: bind error: " << strerror(errno);
   }
-  CHECK_EQ(listen(fd.Get(), kMaxBackLogForSocketListen), 0)
-      << "Endpoint::Endpoint: listen error: " << strerror(errno);
+  Init(std::move(fd));
+}
 
+Endpoint::Endpoint(LocalHandle socket_fd) { Init(std::move(socket_fd)); }
+
+void Endpoint::Init(LocalHandle socket_fd) {
+  if (socket_fd) {
+    CHECK_EQ(listen(socket_fd.Get(), kMaxBackLogForSocketListen), 0)
+        << "Endpoint::Endpoint: listen error: " << strerror(errno);
+  }
   cancel_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   CHECK(cancel_event_fd_.IsValid())
       << "Endpoint::Endpoint: Failed to create event fd: " << strerror(errno);
@@ -172,24 +179,27 @@
   CHECK(epoll_fd_.IsValid())
       << "Endpoint::Endpoint: Failed to create epoll fd: " << strerror(errno);
 
-  epoll_event socket_event;
-  socket_event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
-  socket_event.data.fd = fd.Get();
+  if (socket_fd) {
+    epoll_event socket_event;
+    socket_event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
+    socket_event.data.fd = socket_fd.Get();
+    int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, socket_fd.Get(),
+                        &socket_event);
+    CHECK_EQ(ret, 0)
+        << "Endpoint::Endpoint: Failed to add socket fd to epoll fd: "
+        << strerror(errno);
+  }
 
   epoll_event cancel_event;
   cancel_event.events = EPOLLIN;
   cancel_event.data.fd = cancel_event_fd_.Get();
 
-  int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd.Get(), &socket_event);
-  CHECK_EQ(ret, 0)
-      << "Endpoint::Endpoint: Failed to add socket fd to epoll fd: "
-      << strerror(errno);
-  ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(),
-                  &cancel_event);
+  int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(),
+                      &cancel_event);
   CHECK_EQ(ret, 0)
       << "Endpoint::Endpoint: Failed to add cancel event fd to epoll fd: "
       << strerror(errno);
-  socket_fd_ = std::move(fd);
+  socket_fd_ = std::move(socket_fd);
 }
 
 void* Endpoint::AllocateMessageState() { return new MessageState; }
@@ -199,6 +209,9 @@
 }
 
 Status<void> Endpoint::AcceptConnection(Message* message) {
+  if (!socket_fd_)
+    return ErrorStatus(EBADF);
+
   sockaddr_un remote;
   socklen_t addrlen = sizeof(remote);
   LocalHandle channel_fd{accept4(socket_fd_.Get(),
@@ -515,7 +528,7 @@
     return ErrorStatus{ESHUTDOWN};
   }
 
-  if (event.data.fd == socket_fd_.Get()) {
+  if (socket_fd_ && event.data.fd == socket_fd_.Get()) {
     auto status = AcceptConnection(message);
     if (!status)
       return status;
@@ -680,6 +693,23 @@
       new Endpoint(endpoint_path, blocking, false));
 }
 
+std::unique_ptr<Endpoint> Endpoint::CreateFromSocketFd(LocalHandle socket_fd) {
+  return std::unique_ptr<Endpoint>(new Endpoint(std::move(socket_fd)));
+}
+
+Status<void> Endpoint::RegisterNewChannelForTests(LocalHandle channel_fd) {
+  int optval = 1;
+  if (setsockopt(channel_fd.Get(), SOL_SOCKET, SO_PASSCRED, &optval,
+                 sizeof(optval)) == -1) {
+    ALOGE(
+        "Endpoint::RegisterNewChannelForTests: Failed to enable the receiving"
+        "of the credentials for channel %d: %s",
+        channel_fd.Get(), strerror(errno));
+    return ErrorStatus(errno);
+  }
+  return OnNewChannel(std::move(channel_fd));
+}
+
 }  // namespace uds
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libvrflinger/compositor.cpp b/libs/vr/libvrflinger/compositor.cpp
index 07e4a8b..239ef75 100644
--- a/libs/vr/libvrflinger/compositor.cpp
+++ b/libs/vr/libvrflinger/compositor.cpp
@@ -246,16 +246,17 @@
 
 class Compositor::RenderPoseBufferObject {
  public:
-  RenderPoseBufferObject(LocalHandle&& render_pose_buffer_fd) {
+  RenderPoseBufferObject(LocalHandle&& render_pose_buffer_fd) :
+      fd_(std::move(render_pose_buffer_fd)) {
     // Create new pose tracking buffer for this surface.
     glGenBuffers(1, &render_pose_buffer_object_);
     glBindBuffer(GL_UNIFORM_BUFFER, render_pose_buffer_object_);
-    if (render_pose_buffer_fd) {
+    if (fd_) {
       LOG_ALWAYS_FATAL_IF(!glBindSharedBufferQCOM);
       if (glBindSharedBufferQCOM)
         glBindSharedBufferQCOM(GL_UNIFORM_BUFFER,
                                sizeof(DisplaySurfaceMetadata),
-                               render_pose_buffer_fd.Get());
+                               fd_.Get());
       else
         ALOGE("Error: Missing gralloc buffer extension");
       CHECK_GL();
@@ -271,6 +272,7 @@
   // Render pose buffer object. This contains an array of poses that corresponds
   // with the surface buffers.
   GLuint render_pose_buffer_object_;
+  LocalHandle fd_;
 
   RenderPoseBufferObject(const RenderPoseBufferObject&) = delete;
   void operator=(const RenderPoseBufferObject&) = delete;
@@ -429,6 +431,7 @@
 }
 
 void Compositor::Shutdown() {
+  glFinish();
   render_target_[0].Destroy();
   render_target_[1].Destroy();
   layers_.clear();
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 971345b..d3d50d0 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -209,16 +209,16 @@
   // We should always have a red distortion.
   LOG_FATAL_IF(view_params.distortion_coefficients_r.empty());
   red_distortion = std::make_shared<PolynomialRadialDistortion>(
-      0.0f, view_params.distortion_coefficients_r);
+      view_params.distortion_coefficients_r);
 
   if (!view_params.distortion_coefficients_g.empty()) {
     green_distortion = std::make_shared<PolynomialRadialDistortion>(
-        0.0f, view_params.distortion_coefficients_g);
+        view_params.distortion_coefficients_g);
   }
 
   if (!view_params.distortion_coefficients_b.empty()) {
     blue_distortion = std::make_shared<PolynomialRadialDistortion>(
-        0.0f, view_params.distortion_coefficients_b);
+        view_params.distortion_coefficients_b);
   }
 
   HeadMountMetrics::EyeOrientation left_orientation =
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 080c02b..986c268 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -31,6 +31,7 @@
 using namespace android::hardware::sensors::V1_0;
 using namespace android::hardware::sensors::V1_0::implementation;
 
+
 namespace android {
 // ---------------------------------------------------------------------------
 
@@ -138,20 +139,19 @@
 
         result.append("sampling_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
-            const BatchParams& params = info.batchParams.valueAt(j);
-            result.appendFormat("%.1f%s", params.batchDelay / 1e6f,
+            const BatchParams& params = info.batchParams[j];
+            result.appendFormat("%.1f%s", params.mTSample / 1e6f,
                 j < info.batchParams.size() - 1 ? ", " : "");
         }
-        result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f);
+        result.appendFormat("}, selected = %.2f ms; ", info.bestBatchParams.mTSample / 1e6f);
 
         result.append("batching_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
-            BatchParams params = info.batchParams.valueAt(j);
-
-            result.appendFormat("%.1f%s", params.batchTimeout / 1e6f,
+            const BatchParams& params = info.batchParams[j];
+            result.appendFormat("%.1f%s", params.mTBatch / 1e6f,
                     j < info.batchParams.size() - 1 ? ", " : "");
         }
-        result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
+        result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f);
     }
 
     return result.string();
@@ -270,13 +270,10 @@
                 // batch_rate and timeout. One of the apps has unregistered for sensor
                 // events, and the best effort batch parameters might have changed.
                 ALOGD_IF(DEBUG_CONNECTIONS,
-                         "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
-                         info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
-                         info.bestBatchParams.batchTimeout);
+                         "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64, handle,
+                         info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
                 checkReturn(mSensors->batch(
-                        handle,
-                        info.bestBatchParams.batchDelay,
-                        info.bestBatchParams.batchTimeout));
+                        handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));
             }
         } else {
             // sensor wasn't enabled for this ident
@@ -314,6 +311,9 @@
     if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
         samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
     }
+    if (maxBatchReportLatencyNs < 0) {
+        maxBatchReportLatencyNs = 0;
+    }
 
     ALOGD_IF(DEBUG_CONNECTIONS,
              "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
@@ -323,7 +323,7 @@
     Info& info(mActivationCount.editValueFor(handle));
 
     if (info.batchParams.indexOfKey(ident) < 0) {
-        BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs);
+        BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs);
         info.batchParams.add(ident, params);
     } else {
         // A batch has already been called with this ident. Update the batch parameters.
@@ -337,25 +337,21 @@
     ALOGD_IF(DEBUG_CONNECTIONS,
              "\t>>> curr_period=%" PRId64 " min_period=%" PRId64
              " curr_timeout=%" PRId64 " min_timeout=%" PRId64,
-             prevBestBatchParams.batchDelay, info.bestBatchParams.batchDelay,
-             prevBestBatchParams.batchTimeout, info.bestBatchParams.batchTimeout);
+             prevBestBatchParams.mTSample, info.bestBatchParams.mTSample,
+             prevBestBatchParams.mTBatch, info.bestBatchParams.mTBatch);
 
     status_t err(NO_ERROR);
     // If the min period or min timeout has changed since the last batch call, call batch.
     if (prevBestBatchParams != info.bestBatchParams) {
-        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
-                 info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
-                 info.bestBatchParams.batchTimeout);
+        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH 0x%08x %" PRId64 " %" PRId64, handle,
+                 info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
         err = StatusFromResult(
                 checkReturn(mSensors->batch(
-                    handle,
-                    info.bestBatchParams.batchDelay,
-                    info.bestBatchParams.batchTimeout)));
+                    handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch)));
         if (err != NO_ERROR) {
-            ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
-                  mSensors.get(), handle,
-                  info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
-                  info.bestBatchParams.batchTimeout, strerror(-err));
+            ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
+                  mSensors.get(), handle, info.bestBatchParams.mTSample,
+                  info.bestBatchParams.mTBatch, strerror(-err));
             info.removeBatchParamsForIdent(ident);
         }
     }
@@ -363,28 +359,7 @@
 }
 
 status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
-    if (mSensors == nullptr) return NO_INIT;
-    if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
-        samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
-    }
-    Mutex::Autolock _l(mLock);
-    if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
-    Info& info( mActivationCount.editValueFor(handle) );
-    // If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
-    // Calling setDelay() in batch mode is an invalid operation.
-    if (info.bestBatchParams.batchTimeout != 0) {
-      return INVALID_OPERATION;
-    }
-    ssize_t index = info.batchParams.indexOfKey(ident);
-    if (index < 0) {
-        return BAD_INDEX;
-    }
-    BatchParams& params = info.batchParams.editValueAt(index);
-    params.batchDelay = samplingPeriodNs;
-    info.selectBatchParams();
-
-    return StatusFromResult(
-            checkReturn(mSensors->batch(handle, info.bestBatchParams.batchDelay, 0)));
+    return batch(ident, handle, 0, samplingPeriodNs, 0);
 }
 
 int SensorDevice::getHalDeviceVersion() const {
@@ -423,8 +398,8 @@
         status_t err = StatusFromResult(
                 checkReturn(mSensors->batch(
                     sensor_handle,
-                    info.bestBatchParams.batchDelay,
-                    info.bestBatchParams.batchTimeout)));
+                    info.bestBatchParams.mTSample,
+                    info.bestBatchParams.mTBatch)));
         ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
 
         if (err == NO_ERROR) {
@@ -581,35 +556,35 @@
     return num;
 }
 
-status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
+status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int,
                                                     int64_t samplingPeriodNs,
                                                     int64_t maxBatchReportLatencyNs) {
     ssize_t index = batchParams.indexOfKey(ident);
     if (index < 0) {
-        ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)",
+        ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64
+              " timeout=%" PRId64 ") failed (%s)",
               ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index));
         return BAD_INDEX;
     }
     BatchParams& params = batchParams.editValueAt(index);
-    params.flags = flags;
-    params.batchDelay = samplingPeriodNs;
-    params.batchTimeout = maxBatchReportLatencyNs;
+    params.mTSample = samplingPeriodNs;
+    params.mTBatch = maxBatchReportLatencyNs;
     return NO_ERROR;
 }
 
 void SensorDevice::Info::selectBatchParams() {
-    BatchParams bestParams(0, -1, -1);
+    BatchParams bestParams; // default to max Tsample and max Tbatch
     SensorDevice& device(SensorDevice::getInstance());
 
     for (size_t i = 0; i < batchParams.size(); ++i) {
-        if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
-        BatchParams params = batchParams.valueAt(i);
-        if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
-            bestParams.batchDelay = params.batchDelay;
+        if (device.isClientDisabledLocked(batchParams.keyAt(i))) {
+            continue;
         }
-        if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
-            bestParams.batchTimeout = params.batchTimeout;
-        }
+        bestParams.merge(batchParams[i]);
+    }
+    // if mTBatch <= mTSample, it is in streaming mode. set mTbatch to 0 to demand this explicitly.
+    if (bestParams.mTBatch <= bestParams.mTSample) {
+        bestParams.mTBatch = 0;
     }
     bestBatchParams = bestParams;
 }
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 2520a81..fd6cee6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -27,7 +27,8 @@
 #include <utils/String8.h>
 
 #include <string>
-#include <map>
+#include <unordered_map>
+#include <algorithm> //std::max std::min
 
 #include "android/hardware/sensors/1.0/ISensors.h"
 
@@ -106,7 +107,7 @@
 
     sp<android::hardware::sensors::V1_0::ISensors> mSensors;
     Vector<sensor_t> mSensorList;
-    std::map<int32_t, sensor_t*> mConnectedDynamicSensors;
+    std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
 
     static const nsecs_t MINIMUM_EVENTS_PERIOD =   1000000; // 1000 Hz
     mutable Mutex mLock; // protect mActivationCount[].batchParams
@@ -115,15 +116,18 @@
     // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from
     // batch call. For continous mode clients, maxBatchReportLatency is set to zero.
     struct BatchParams {
-      // TODO: Get rid of flags parameter everywhere.
-      int flags;
-      nsecs_t batchDelay, batchTimeout;
-      BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {}
-      BatchParams(int flag, nsecs_t delay, nsecs_t timeout): flags(flag), batchDelay(delay),
-          batchTimeout(timeout) { }
+      nsecs_t mTSample, mTBatch;
+      BatchParams() : mTSample(INT64_MAX), mTBatch(INT64_MAX) {}
+      BatchParams(nsecs_t tSample, nsecs_t tBatch): mTSample(tSample), mTBatch(tBatch) {}
       bool operator != (const BatchParams& other) {
-          return other.batchDelay != batchDelay || other.batchTimeout != batchTimeout ||
-                 other.flags != flags;
+          return !(mTSample == other.mTSample && mTBatch == other.mTBatch);
+      }
+      // Merge another parameter with this one. The updated mTSample will be the min of the two.
+      // The update mTBatch will be the min of original mTBatch and the apparent batch period
+      // of the other. the apparent batch is the maximum of mTBatch and mTSample,
+      void merge(const BatchParams &other) {
+          mTSample = std::min(mTSample, other.mTSample);
+          mTBatch = std::min(mTBatch, std::max(other.mTBatch, other.mTSample));
       }
     };
 
@@ -139,7 +143,6 @@
         // requested by the client.
         KeyedVector<void*, BatchParams> batchParams;
 
-        Info() : bestBatchParams(0, -1, -1) {}
         // Sets batch parameters for this ident. Returns error if this ident is not already present
         // in the KeyedVector above.
         status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs,
diff --git a/services/sensorservice/hidl/EventQueue.cpp b/services/sensorservice/hidl/EventQueue.cpp
index c0365e5..ff20066 100644
--- a/services/sensorservice/hidl/EventQueue.cpp
+++ b/services/sensorservice/hidl/EventQueue.cpp
@@ -27,7 +27,8 @@
 
 class EventQueueLooperCallback : public ::android::LooperCallback {
 public:
-    EventQueueLooperCallback(sp<EventQueue> queue, sp<IEventQueueCallback> callback)
+    EventQueueLooperCallback(sp<::android::SensorEventQueue> queue,
+                             sp<IEventQueueCallback> callback)
             : mQueue(queue), mCallback(callback) {
     }
 
@@ -35,7 +36,11 @@
 
         ASensorEvent event;
         ssize_t actual;
-        const sp<::android::SensorEventQueue>& internalQueue = mQueue->mInternalQueue;
+
+        auto internalQueue = mQueue.promote();
+        if (internalQueue == nullptr) {
+            return 1;
+        }
 
         while ((actual = internalQueue->read(&event, 1 /* count */)) > 0) {
             internalQueue->sendAck(&event, actual);
@@ -47,7 +52,7 @@
     }
 
 private:
-    sp<EventQueue> mQueue;
+    wp<::android::SensorEventQueue> mQueue;
     sp<IEventQueueCallback> mCallback;
 };
 
@@ -58,18 +63,18 @@
             : mLooper(looper),
               mInternalQueue(internalQueue) {
 
-    mLooper->addFd(mInternalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
-            new EventQueueLooperCallback(this, callback), NULL /* data */);
+    mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
+            new EventQueueLooperCallback(internalQueue, callback), NULL /* data */);
 }
 
-EventQueue::~EventQueue() {
+void EventQueue::onLastStrongRef(const void *id) {
+    IEventQueue::onLastStrongRef(id);
     mLooper->removeFd(mInternalQueue->getFd());
 }
 
 // Methods from ::android::frameworks::sensorservice::V1_0::IEventQueue follow.
 Return<Result> EventQueue::enableSensor(int32_t sensorHandle, int32_t samplingPeriodUs,
         int64_t maxBatchReportLatencyUs) {
-    // TODO implement
     return convertResult(mInternalQueue->enableSensor(sensorHandle, samplingPeriodUs,
             maxBatchReportLatencyUs, 0 /* reserved flags */));
 }
diff --git a/services/sensorservice/hidl/EventQueue.h b/services/sensorservice/hidl/EventQueue.h
index 87c614b..6be03b7 100644
--- a/services/sensorservice/hidl/EventQueue.h
+++ b/services/sensorservice/hidl/EventQueue.h
@@ -42,7 +42,7 @@
         sp<IEventQueueCallback> callback,
         sp<::android::Looper> looper,
         sp<::android::SensorEventQueue> internalQueue);
-    ~EventQueue();
+    void onLastStrongRef(const void *) override;
 
     // Methods from ::android::frameworks::sensorservice::V1_0::IEventQueue follow.
     Return<Result> enableSensor(int32_t sensorHandle, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs) override;