(reland 3) Upgrade sensors to @2.0

Notices:
* a.h.sensors@2.0-impl.ranchu is installed into
  /vendor/lib(64)? instead of /vendor/lib(64)?/hw
  because a.h.sensors@2.0-service.multihal does not
  look for libraries in the hw directories unless
  full path is provided and it is bitness-dependent,
  see b/154634207.

* hals.conf is placed into the etc directory using
  PRODUCT_COPY_FILES instead of prebuilt_etc due
  to technical debt in our build files around wifi
  HAL libraris. aosp/1293093 has to be landed
  properly to resolve this, see aosp/1293576.

Bug: 153754380
Bug: 154634207
Test: atest VtsHalSensorsV2_0TargetTest
Signed-off-by: Roman Kiryanov <rkir@google.com>
Merged-In: I4be34db36763857d2d5428afe3e2c8d0b743b609
Change-Id: I275a313d4de2814ac25a674f02539e8431c0e651
diff --git a/manifest.sensors.xml b/manifest.sensors.xml
deleted file mode 100644
index 1c0a50b..0000000
--- a/manifest.sensors.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="device" target-level="3">
-    <hal format="hidl">
-        <name>android.hardware.sensors</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>ISensors</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/sensors/Android.bp b/sensors/Android.bp
new file mode 100644
index 0000000..1c07b59
--- /dev/null
+++ b/sensors/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_library_shared {
+    name: "android.hardware.sensors@2.0-impl.ranchu",
+    vendor: true,
+//    relative_install_path: "hw",  // see  b/154634207
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "multihal_sensors.cpp",
+        "multihal_sensors_epoll.cpp",
+        "multihal_sensors_qemu.cpp",
+        "sensor_list.cpp",
+        "util.cpp",
+        "entry.cpp"
+    ],
+    shared_libs: [
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    header_libs: ["android.hardware.sensors@2.0-multihal.header"],
+    cflags: [
+        "-DLOG_TAG=\"android.hardware.sensors@2.0-impl.ranchu\"",
+        "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+    ],
+}
diff --git a/sensors/Android.mk b/sensors/Android.mk
deleted file mode 100644
index d35f337..0000000
--- a/sensors/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-LOCAL_PATH := $(call my-dir)
-
-# HAL module implemenation stored in
-# hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.hardware>.so
-
-include $(CLEAR_VARS)
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SHARED_LIBRARIES := liblog libcutils
-LOCAL_HEADER_LIBRARIES := libhardware_headers
-LOCAL_C_INCLUDES += \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../../goldfish-opengl/shared/OpenglCodecCommon
-LOCAL_SRC_FILES := sensors_qemu.c
-LOCAL_MODULE := sensors.ranchu
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/sensors/entry.cpp b/sensors/entry.cpp
new file mode 100644
index 0000000..bc14194
--- /dev/null
+++ b/sensors/entry.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+#include "multihal_sensors.h"
+
+namespace {
+goldfish::MultihalSensors impl;
+}
+
+extern "C" ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+    *version = SUB_HAL_2_0_VERSION;
+    return &impl;
+}
diff --git a/sensors/hals.conf b/sensors/hals.conf
new file mode 100644
index 0000000..d5dcc83
--- /dev/null
+++ b/sensors/hals.conf
@@ -0,0 +1 @@
+android.hardware.sensors@2.0-impl.ranchu.so
diff --git a/sensors/multihal_sensors.cpp b/sensors/multihal_sensors.cpp
new file mode 100644
index 0000000..f0012cf
--- /dev/null
+++ b/sensors/multihal_sensors.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cinttypes>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include "multihal_sensors.h"
+#include "sensor_list.h"
+#include "util.h"
+
+namespace goldfish {
+using ahs10::SensorType;
+using ahs10::SensorFlagBits;
+using ahs10::MetaDataEventType;
+
+MultihalSensors::MultihalSensors() : m_qemuSensorsFd(qemud_channel_open("sensors")) {
+    if (!m_qemuSensorsFd.ok()) {
+        ALOGE("%s:%d: m_qemuSensorsFd is not opened", __func__, __LINE__);
+        ::abort();
+    }
+
+    char buffer[64];
+    int len = snprintf(buffer, sizeof(buffer),
+                       "time:%" PRId64, ::android::elapsedRealtimeNano());
+    if (qemud_channel_send(m_qemuSensorsFd.get(), buffer, len) < 0) {
+        ALOGE("%s:%d: qemud_channel_send failed", __func__, __LINE__);
+        ::abort();
+    }
+
+    using namespace std::literals;
+    const std::string_view kListSensorsCmd = "list-sensors"sv;
+
+    if (qemud_channel_send(m_qemuSensorsFd.get(),
+                           kListSensorsCmd.data(),
+                           kListSensorsCmd.size()) < 0) {
+        ALOGE("%s:%d: qemud_channel_send failed", __func__, __LINE__);
+        ::abort();
+    }
+
+    len = qemud_channel_recv(m_qemuSensorsFd.get(), buffer, sizeof(buffer) - 1);
+    if (len < 0) {
+        ALOGE("%s:%d: qemud_channel_recv failed", __func__, __LINE__);
+        ::abort();
+    }
+    buffer[len] = 0;
+    uint32_t availableSensorsMask = 0;
+    if (sscanf(buffer, "%u", &availableSensorsMask) != 1) {
+        ALOGE("%s:%d: Can't parse qemud response", __func__, __LINE__);
+        ::abort();
+    }
+    m_availableSensorsMask =
+        availableSensorsMask & ((1u << getSensorNumber()) - 1);
+
+    if (!::android::base::Socketpair(AF_LOCAL, SOCK_STREAM, 0,
+                                     &m_callersFd, &m_sensorThreadFd)) {
+        ALOGE("%s:%d: Socketpair failed", __func__, __LINE__);
+        ::abort();
+    }
+
+    m_sensorThread = std::thread(qemuSensorListenerThreadStart, this);
+}
+
+MultihalSensors::~MultihalSensors() {
+    disableAllSensors();
+    qemuSensorThreadSendCommand(kCMD_QUIT);
+    m_sensorThread.join();
+}
+
+const std::string MultihalSensors::getName() {
+    return "hal_sensors_2_0_impl_ranchu";
+}
+
+Return<void> MultihalSensors::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+    (void)fd;
+    (void)args;
+    return {};
+}
+
+Return<void> MultihalSensors::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+
+    uint32_t mask = m_availableSensorsMask;
+    for (int i = 0; mask; ++i, mask >>= 1) {
+        if (mask & 1) {
+            sensors.push_back(*getSensorInfoByHandle(i));
+        }
+    }
+
+    _hidl_cb(sensors);
+    return {};
+}
+
+Return<Result> MultihalSensors::setOperationMode(const OperationMode mode) {
+    std::unique_lock<std::mutex> lock(m_apiMtx);
+
+    if (m_activeSensorsMask) {
+        return Result::INVALID_OPERATION;
+    } else {
+        m_opMode = mode;
+        return Result::OK;
+    }
+}
+
+Return<Result> MultihalSensors::activate(const int32_t sensorHandle,
+                                         const bool enabled) {
+    if (!isSensorHandleValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(m_apiMtx);
+
+    uint32_t newActiveMask;
+    if (enabled) {
+        newActiveMask = m_activeSensorsMask | (1u << sensorHandle);
+    } else {
+        newActiveMask = m_activeSensorsMask & ~(1u << sensorHandle);
+    }
+    if (m_activeSensorsMask == newActiveMask) {
+        return Result::OK;
+    }
+
+    if (m_opMode == OperationMode::NORMAL) {
+        if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), sensorHandle, enabled)) {
+            return Result::INVALID_OPERATION;
+        }
+    }
+
+    m_activeSensorsMask = newActiveMask;
+    return Result::OK;
+}
+
+Return<Result> MultihalSensors::batch(const int32_t sensorHandle,
+                                      const int64_t samplingPeriodNs,
+                                      const int64_t maxReportLatencyNs) {
+    (void)maxReportLatencyNs;
+
+    const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
+    if (sensor) {
+        if (samplingPeriodNs >= sensor->minDelay) {
+            return Result::OK;
+        } else {
+            return Result::BAD_VALUE;
+        }
+    } else {
+        return Result::BAD_VALUE;
+    }
+}
+
+Return<Result> MultihalSensors::flush(const int32_t sensorHandle) {
+    const SensorInfo* sensor = getSensorInfoByHandle(sensorHandle);
+    if (!sensor) {
+        return Result::BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(m_apiMtx);
+    if (!(m_activeSensorsMask & (1u << sensorHandle))) {
+        return Result::BAD_VALUE;
+    }
+
+    Event event;
+    event.sensorHandle = sensorHandle;
+    event.sensorType = SensorType::META_DATA;
+    event.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+
+    postSensorEventLocked(event);
+    return Result::OK;
+}
+
+Return<Result> MultihalSensors::injectSensorData(const Event& event) {
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        return Result::OK;
+    }
+
+    std::unique_lock<std::mutex> lock(m_apiMtx);
+    if (m_opMode != OperationMode::DATA_INJECTION) {
+        return Result::INVALID_OPERATION;
+    }
+    const SensorInfo* sensor = getSensorInfoByHandle(event.sensorHandle);
+    if (!sensor) {
+        return Result::BAD_VALUE;
+    }
+    if (sensor->type != event.sensorType) {
+        return Result::BAD_VALUE;
+    }
+
+    postSensorEventLocked(event);
+    return Result::OK;
+}
+
+Return<Result> MultihalSensors::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
+    std::unique_lock<std::mutex> lock(m_apiMtx);
+    disableAllSensors();
+    m_opMode = OperationMode::NORMAL;
+    m_halProxyCallback = halProxyCallback;
+    return Result::OK;
+}
+
+void MultihalSensors::postSensorEvent(const Event& event) {
+    std::unique_lock<std::mutex> lock(m_apiMtx);
+    postSensorEventLocked(event);
+}
+
+void MultihalSensors::postSensorEventLocked(const Event& event) {
+    const bool isWakeupEvent =
+        getSensorInfoByHandle(event.sensorHandle)->flags &
+        static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+
+    m_halProxyCallback->postEvents(
+        {event},
+        m_halProxyCallback->createScopedWakelock(isWakeupEvent));
+}
+
+bool MultihalSensors::qemuSensorThreadSendCommand(const char cmd) const {
+    return TEMP_FAILURE_RETRY(write(m_callersFd.get(), &cmd, 1)) == 1;
+}
+
+/// not supported //////////////////////////////////////////////////////////////
+Return<void> MultihalSensors::registerDirectChannel(const SharedMemInfo& mem,
+                                                    registerDirectChannel_cb _hidl_cb) {
+    (void)mem;
+    _hidl_cb(Result::INVALID_OPERATION, -1);
+    return {};
+}
+
+Return<Result> MultihalSensors::unregisterDirectChannel(int32_t channelHandle) {
+    (void)channelHandle;
+    return Result::INVALID_OPERATION;
+}
+
+Return<void> MultihalSensors::configDirectReport(int32_t sensorHandle,
+                                                 int32_t channelHandle,
+                                                 RateLevel rate,
+                                                 configDirectReport_cb _hidl_cb) {
+    (void)sensorHandle;
+    (void)channelHandle;
+    (void)rate;
+    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+    return {};
+}
+
+}  // namespace goldfish
diff --git a/sensors/multihal_sensors.h b/sensors/multihal_sensors.h
new file mode 100644
index 0000000..dbdc134
--- /dev/null
+++ b/sensors/multihal_sensors.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android-base/unique_fd.h>
+#include <SubHal.h>
+#include <cstdint>
+#include <thread>
+
+namespace goldfish {
+namespace ahs = ::android::hardware::sensors;
+namespace ahs20 = ahs::V2_0;
+namespace ahs10 = ahs::V1_0;
+
+using ahs20::implementation::IHalProxyCallback;
+using ahs10::Event;
+using ahs10::OperationMode;
+using ahs10::RateLevel;
+using ahs10::Result;
+using ahs10::SharedMemInfo;
+
+using ::android::base::unique_fd;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::sp;
+
+struct MultihalSensors : public ahs20::implementation::ISensorsSubHal {
+    MultihalSensors();
+    ~MultihalSensors();
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+    Return<Result> setOperationMode(OperationMode mode) override;
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+    Return<Result> batch(int32_t sensorHandle,
+                           int64_t samplingPeriodNs,
+                           int64_t maxReportLatencyNs) override;
+    Return<Result> flush(int32_t sensorHandle) override;
+    Return<Result> injectSensorData(const Event& event) override;
+
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       registerDirectChannel_cb _hidl_cb) override;
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+    Return<void> configDirectReport(int32_t sensorHandle,
+                                    int32_t channelHandle,
+                                    RateLevel rate,
+                                    configDirectReport_cb _hidl_cb) override;
+
+    const std::string getName() override;
+    Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
+
+private:
+    struct QemuSensorsProtocolState {
+        int64_t timeBiasNs = -500000000;
+
+        static constexpr float kSensorNoValue = -1e+30;
+
+        // on change sensors (host does not support them)
+        float lastAmbientTemperatureValue = kSensorNoValue;
+        float lastProximityValue = kSensorNoValue;
+        float lastLightValue = kSensorNoValue;
+        float lastRelativeHumidityValue = kSensorNoValue;
+    };
+
+    static bool activateQemuSensorImpl(int pipe, int sensorHandle, bool enabled);
+    bool disableAllSensors();
+    void parseQemuSensorEvent(const int pipe, QemuSensorsProtocolState* state);
+    void postSensorEvent(const Event& event);
+    void postSensorEventLocked(const Event& event);
+
+    void qemuSensorListenerThread();
+    static void qemuSensorListenerThreadStart(MultihalSensors* that);
+
+    static constexpr char kCMD_QUIT = 'q';
+    bool qemuSensorThreadSendCommand(char cmd) const;
+
+    // set in ctor, never change
+    const unique_fd     m_qemuSensorsFd;
+    uint32_t            m_availableSensorsMask = 0;
+    // a pair of connected sockets to talk to the worker thread
+    unique_fd           m_callersFd;        // a caller writes here
+    unique_fd           m_sensorThreadFd;   // the worker thread listens from here
+    std::thread         m_sensorThread;
+
+    // changed by API
+    uint32_t                m_activeSensorsMask = 0;
+    OperationMode           m_opMode = OperationMode::NORMAL;
+    sp<IHalProxyCallback>   m_halProxyCallback;
+    mutable std::mutex      m_apiMtx;
+};
+
+}  // namespace goldfish
diff --git a/sensors/multihal_sensors_epoll.cpp b/sensors/multihal_sensors_epoll.cpp
new file mode 100644
index 0000000..739d05b
--- /dev/null
+++ b/sensors/multihal_sensors_epoll.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+#include <sys/epoll.h>
+#include "multihal_sensors.h"
+#include "util.h"
+
+namespace goldfish {
+
+namespace {
+int epollCtlAdd(int epollFd, int fd) {
+    struct epoll_event ev;
+    ev.events  = EPOLLIN;
+    ev.data.fd = fd;
+    return TEMP_FAILURE_RETRY(epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev));
+}
+
+int qemuSensortThreadRcvCommand(const int fd) {
+    char buf;
+    if (TEMP_FAILURE_RETRY(read(fd, &buf, 1)) == 1) {
+        return buf;
+    } else {
+        return -1;
+    }
+}
+}  // namespace
+
+void MultihalSensors::qemuSensorListenerThreadStart(MultihalSensors* that) {
+    that->qemuSensorListenerThread();
+}
+
+void MultihalSensors::qemuSensorListenerThread() {
+    const unique_fd epollFd(epoll_create1(0));
+    if (!epollFd.ok()) {
+        ALOGE("%s:%d: epoll_create1 failed", __func__, __LINE__);
+        ::abort();
+    }
+
+    epollCtlAdd(epollFd.get(), m_qemuSensorsFd.get());
+    epollCtlAdd(epollFd.get(), m_sensorThreadFd.get());
+
+    QemuSensorsProtocolState protocolState;
+
+    while (true) {
+        struct epoll_event events[2];
+        const int kTimeoutMs = 60000;
+        const int n = TEMP_FAILURE_RETRY(epoll_wait(epollFd.get(),
+                                                    events, 2,
+                                                    kTimeoutMs));
+        if (n < 0) {
+            ALOGE("%s:%d: epoll_wait failed with '%s'",
+                  __func__, __LINE__, strerror(errno));
+            continue;
+        }
+
+        for (int i = 0; i < n; ++i) {
+            const struct epoll_event* ev = &events[i];
+            const int fd = ev->data.fd;
+            const int ev_events = ev->events;
+
+            if (fd == m_qemuSensorsFd.get()) {
+                if (ev_events & (EPOLLERR | EPOLLHUP)) {
+                    ALOGE("%s:%d: epoll_wait: devFd has an error, ev_events=%x",
+                          __func__, __LINE__, ev_events);
+                    ::abort();
+                } else if (ev_events & EPOLLIN) {
+                    parseQemuSensorEvent(m_qemuSensorsFd.get(), &protocolState);
+                }
+            } else if (fd == m_sensorThreadFd.get()) {
+                if (ev_events & (EPOLLERR | EPOLLHUP)) {
+                    ALOGE("%s:%d: epoll_wait: threadsFd has an error, ev_events=%x",
+                          __func__, __LINE__, ev_events);
+                    ::abort();
+                } else if (ev_events & EPOLLIN) {
+                    const int cmd = qemuSensortThreadRcvCommand(fd);
+                    if (cmd == kCMD_QUIT) {
+                        return;
+                    } else {
+                        ALOGE("%s:%d: qemuSensortThreadRcvCommand returned unexpected command, cmd=%d",
+                              __func__, __LINE__, cmd);
+                        ::abort();
+                    }
+                }
+            } else {
+                ALOGE("%s:%d: epoll_wait() returned unexpected fd",
+                      __func__, __LINE__);
+            }
+        }
+    }
+}
+
+}  // namespace goldfish
diff --git a/sensors/multihal_sensors_qemu.cpp b/sensors/multihal_sensors_qemu.cpp
new file mode 100644
index 0000000..6e802e6
--- /dev/null
+++ b/sensors/multihal_sensors_qemu.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <math.h>
+#include "multihal_sensors.h"
+#include "sensor_list.h"
+#include "util.h"
+
+namespace goldfish {
+using ahs10::EventPayload;
+using ahs10::SensorType;
+using ahs10::SensorStatus;
+
+namespace {
+const char* testPrefix(const char* i, const char* end, const char* v, const char sep) {
+    while (i < end) {
+        if (*v == 0) {
+            return (*i == sep) ? (i + 1) : nullptr;
+        } else if (*v == *i) {
+            ++v;
+            ++i;
+        } else {
+            return nullptr;
+        }
+    }
+
+    return nullptr;
+}
+
+bool approximatelyEqual(double a, double b, double eps) {
+    return fabs(a - b) <= std::max(fabs(a), fabs(b)) * eps;
+}
+
+int64_t weigthedAverage(const int64_t a, int64_t aw, int64_t b, int64_t bw) {
+    return (a * aw + b * bw) / (aw + bw);
+}
+
+}  // namespace
+
+bool MultihalSensors::activateQemuSensorImpl(const int pipe,
+                                             const int sensorHandle,
+                                             const bool enabled) {
+    char buffer[64];
+    int len = snprintf(buffer, sizeof(buffer),
+                       "set:%s:%d",
+                       getQemuSensorNameByHandle(sensorHandle),
+                       (enabled ? 1 : 0));
+
+    if (qemud_channel_send(pipe, buffer, len) < 0) {
+        ALOGE("%s:%d: qemud_channel_send failed", __func__, __LINE__);
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool MultihalSensors::disableAllSensors() {
+    if (m_opMode == OperationMode::NORMAL) {
+        uint32_t mask = m_activeSensorsMask;
+        for (int i = 0; mask; ++i, mask >>= 1) {
+            if (mask & 1) {
+                if (!activateQemuSensorImpl(m_qemuSensorsFd.get(), i, false)) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    m_activeSensorsMask = 0;
+    return true;
+}
+
+void MultihalSensors::parseQemuSensorEvent(const int pipe,
+                                           QemuSensorsProtocolState* state) {
+    char buf[256];
+    const int len = qemud_channel_recv(pipe, buf, sizeof(buf) - 1);
+    if (len < 0) {
+        ALOGE("%s:%d: qemud_channel_recv failed", __func__, __LINE__);
+    }
+    const int64_t nowNs = ::android::elapsedRealtimeNano();
+    buf[len] = 0;
+    const char* end = buf + len;
+
+    bool parsed = false;
+    Event event;
+    EventPayload* payload = &event.u;
+    ahs10::Vec3* vec3 = &payload->vec3;
+    ahs10::Uncal* uncal = &payload->uncal;
+
+    if (const char* values = testPrefix(buf, end, "acceleration", ':')) {
+        if (sscanf(values, "%f:%f:%f",
+                   &vec3->x, &vec3->y, &vec3->z) == 3) {
+            vec3->status = SensorStatus::ACCURACY_MEDIUM;
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandleAccelerometer;
+            event.sensorType = SensorType::ACCELEROMETER;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "gyroscope", ':')) {
+        if (sscanf(values, "%f:%f:%f",
+                   &vec3->x, &vec3->y, &vec3->z) == 3) {
+            vec3->status = SensorStatus::ACCURACY_MEDIUM;
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandleGyroscope;
+            event.sensorType = SensorType::GYROSCOPE;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "gyroscope-uncalibrated", ':')) {
+        if (sscanf(values, "%f:%f:%f",
+                   &uncal->x, &uncal->y, &uncal->z) == 3) {
+            uncal->x_bias = 0.0;
+            uncal->y_bias = 0.0;
+            uncal->z_bias = 0.0;
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandleGyroscopeFieldUncalibrated;
+            event.sensorType = SensorType::GYROSCOPE_UNCALIBRATED;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "orientation", ':')) {
+        if (sscanf(values, "%f:%f:%f",
+                   &vec3->x, &vec3->y, &vec3->z) == 3) {
+            vec3->status = SensorStatus::ACCURACY_HIGH;
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandleOrientation;
+            event.sensorType = SensorType::ORIENTATION;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "magnetic", ':')) {
+        if (sscanf(values, "%f:%f:%f",
+                   &vec3->x, &vec3->y, &vec3->z) == 3) {
+            vec3->status = SensorStatus::ACCURACY_HIGH;
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandleMagneticField;
+            event.sensorType = SensorType::MAGNETIC_FIELD;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "magnetic-uncalibrated", ':')) {
+        if (sscanf(values, "%f:%f:%f",
+                   &uncal->x, &uncal->y, &uncal->z) == 3) {
+            uncal->x_bias = 0.0;
+            uncal->y_bias = 0.0;
+            uncal->z_bias = 0.0;
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandleMagneticFieldUncalibrated;
+            event.sensorType = SensorType::MAGNETIC_FIELD_UNCALIBRATED;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "temperature", ':')) {
+        if (sscanf(values, "%f", &payload->scalar) == 1) {
+            if (!approximatelyEqual(state->lastAmbientTemperatureValue,
+                                    payload->scalar, 0.001)) {
+                event.timestamp = nowNs + state->timeBiasNs;
+                event.sensorHandle = kSensorHandleAmbientTemperature;
+                event.sensorType = SensorType::AMBIENT_TEMPERATURE;
+                postSensorEvent(event);
+                state->lastAmbientTemperatureValue = payload->scalar;
+            }
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "proximity", ':')) {
+        if (sscanf(values, "%f", &payload->scalar) == 1) {
+            if (!approximatelyEqual(state->lastProximityValue,
+                                    payload->scalar, 0.001)) {
+                event.timestamp = nowNs + state->timeBiasNs;
+                event.sensorHandle = kSensorHandleProximity;
+                event.sensorType = SensorType::PROXIMITY;
+                postSensorEvent(event);
+                state->lastProximityValue = payload->scalar;
+            }
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "light", ':')) {
+        if (sscanf(values, "%f", &payload->scalar) == 1) {
+            if (!approximatelyEqual(state->lastLightValue,
+                                    payload->scalar, 0.001)) {
+                event.timestamp = nowNs + state->timeBiasNs;
+                event.sensorHandle = kSensorHandleLight;
+                event.sensorType = SensorType::LIGHT;
+                postSensorEvent(event);
+                state->lastLightValue = payload->scalar;
+            }
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "pressure", ':')) {
+        if (sscanf(values, "%f", &payload->scalar) == 1) {
+            event.timestamp = nowNs + state->timeBiasNs;
+            event.sensorHandle = kSensorHandlePressure;
+            event.sensorType = SensorType::PRESSURE;
+            postSensorEvent(event);
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "humidity", ':')) {
+        if (sscanf(values, "%f", &payload->scalar) == 1) {
+            if (!approximatelyEqual(state->lastRelativeHumidityValue,
+                                    payload->scalar, 0.001)) {
+                event.timestamp = nowNs + state->timeBiasNs;
+                event.sensorHandle = kSensorHandleRelativeHumidity;
+                event.sensorType = SensorType::RELATIVE_HUMIDITY;
+                postSensorEvent(event);
+                state->lastRelativeHumidityValue = payload->scalar;
+            }
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "guest-sync", ':')) {
+        long long value;
+        if ((sscanf(values, "%lld", &value) == 1) && (value >= 0)) {
+            const int64_t guestTimeNs = static_cast<int64_t>(value * 1000ll);
+            const int64_t timeBiasNs = guestTimeNs - nowNs;
+            state->timeBiasNs =
+                std::min(int64_t(0),
+                         weigthedAverage(state->timeBiasNs, 3, timeBiasNs, 1));
+            parsed = true;
+        }
+    } else if (const char* values = testPrefix(buf, end, "sync", ':')) {
+        parsed = true;
+    }
+
+    if (!parsed) {
+        ALOGW("%s:%d: don't know how to parse '%s'", __func__, __LINE__, buf);
+    }
+}
+
+}  // namespace
diff --git a/sensors/sensor_list.cpp b/sensors/sensor_list.cpp
new file mode 100644
index 0000000..85a5709
--- /dev/null
+++ b/sensors/sensor_list.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sensor_list.h"
+
+namespace goldfish {
+using ahs::V1_0::SensorType;
+using ahs::V1_0::SensorFlagBits;
+
+constexpr char kAospVendor[] = "The Android Open Source Project";
+
+const char* const kQemuSensorName[] = {
+    "acceleration",
+    "gyroscope",
+    "magnetic-field",
+    "orientation",
+    "temperature",
+    "proximity",
+    "light",
+    "pressure",
+    "humidity",
+    "magnetic-field-uncalibrated",
+    "gyroscope-uncalibrated",
+};
+
+const SensorInfo kAllSensors[] = {
+    {
+        .sensorHandle = kSensorHandleAccelerometer,
+        .name = "Goldfish 3-axis Accelerometer",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::ACCELEROMETER,
+        .typeAsString = "android.sensor.accelerometer",
+        .maxRange = 39.3,
+        .resolution = 1.0 / 4032.0,
+        .power = 3.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::CONTINUOUS_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleGyroscope,
+        .name = "Goldfish 3-axis Gyroscope",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::GYROSCOPE,
+        .typeAsString = "android.sensor.gyroscope",
+        .maxRange = 16.46,
+        .resolution = 1.0 / 1000.0,
+        .power = 3.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::CONTINUOUS_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleMagneticField,
+        .name = "Goldfish 3-axis Magnetic field sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::MAGNETIC_FIELD,
+        .typeAsString = "android.sensor.magnetic_field",
+        .maxRange = 2000.0,
+        .resolution = .5,
+        .power = 6.7,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::CONTINUOUS_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleOrientation,
+        .name = "Goldfish Orientation sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::ORIENTATION,
+        .typeAsString = "android.sensor.orientation",
+        .maxRange = 360.0,
+        .resolution = 1.0,
+        .power = 9.7,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::CONTINUOUS_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleAmbientTemperature,
+        .name = "Goldfish Ambient Temperature sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::AMBIENT_TEMPERATURE,
+        .typeAsString = "android.sensor.ambient_temperature",
+        .maxRange = 80.0,
+        .resolution = 1.0,
+        .power = 0.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::ON_CHANGE_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleProximity,
+        .name = "Goldfish Proximity sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::PROXIMITY,
+        .typeAsString = "android.sensor.proximity",
+        .maxRange = 1.0,
+        .resolution = 1.0,
+        .power = 20.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::ON_CHANGE_MODE |
+                 SensorFlagBits::WAKE_UP
+    },
+    {
+        .sensorHandle = kSensorHandleLight,
+        .name = "Goldfish Light sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::LIGHT,
+        .typeAsString = "android.sensor.light",
+        .maxRange = 40000.0,
+        .resolution = 1.0,
+        .power = 20.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::ON_CHANGE_MODE
+    },
+    {
+        .sensorHandle = kSensorHandlePressure,
+        .name = "Goldfish Pressure sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::PRESSURE,
+        .typeAsString = "android.sensor.pressure",
+        .maxRange = 800.0,
+        .resolution = 1.0,
+        .power = 20.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::CONTINUOUS_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleRelativeHumidity,
+        .name = "Goldfish Humidity sensor",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::RELATIVE_HUMIDITY,
+        .typeAsString = "android.sensor.relative_humidity",
+        .maxRange = 100.0,
+        .resolution = 1.0,
+        .power = 20.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::ON_CHANGE_MODE
+    },
+    {
+        .sensorHandle = kSensorHandleMagneticFieldUncalibrated,
+        .name = "Goldfish 3-axis Magnetic field sensor (uncalibrated)",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::MAGNETIC_FIELD_UNCALIBRATED,
+        .typeAsString = "android.sensor.magnetic_field_uncalibrated",
+        .maxRange = 2000.0,
+        .resolution = 0.5,
+        .power = 6.7,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION | 0
+    },
+    {
+        .sensorHandle = kSensorHandleGyroscopeFieldUncalibrated,
+        .name = "Goldfish 3-axis Gyroscope (uncalibrated)",
+        .vendor = kAospVendor,
+        .version = 1,
+        .type = SensorType::GYROSCOPE_UNCALIBRATED,
+        .typeAsString = "android.sensor.gyroscope_uncalibrated",
+        .maxRange = 16.46,
+        .resolution = 1.0 / 1000.0,
+        .power = 3.0,
+        .minDelay = 10000,
+        .fifoReservedEventCount = 0,
+        .fifoMaxEventCount = 0,
+        .requiredPermission = "",
+        .maxDelay = 500000,
+        .flags = SensorFlagBits::DATA_INJECTION |
+                 SensorFlagBits::CONTINUOUS_MODE
+    },
+};
+
+constexpr int kSensorNumber = sizeof(kAllSensors) / sizeof(kAllSensors[0]);
+
+static_assert(kSensorNumber == sizeof(kQemuSensorName) / sizeof(kQemuSensorName[0]),
+              "sizes of kAllSensors and kQemuSensorName arrays must match");
+
+int getSensorNumber() { return kSensorNumber; }
+
+bool isSensorHandleValid(const int h) {
+    return h >= 0 && h < kSensorNumber;
+}
+
+const SensorInfo* getSensorInfoByHandle(const int h) {
+    return isSensorHandleValid(h) ? &kAllSensors[h] : nullptr;
+}
+
+const char* getQemuSensorNameByHandle(const int h) {
+    return kQemuSensorName[h];
+}
+
+}  // namespace goldfish
diff --git a/sensors/sensor_list.h b/sensors/sensor_list.h
new file mode 100644
index 0000000..5eb9d83
--- /dev/null
+++ b/sensors/sensor_list.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android/hardware/sensors/1.0/types.h>
+
+namespace goldfish {
+
+namespace ahs = ::android::hardware::sensors;
+using SensorInfo = ahs::V1_0::SensorInfo;
+
+constexpr int kSensorHandleAccelerometer = 0;
+constexpr int kSensorHandleGyroscope = 1;
+constexpr int kSensorHandleMagneticField = 2;
+constexpr int kSensorHandleOrientation = 3;
+constexpr int kSensorHandleAmbientTemperature = 4;
+constexpr int kSensorHandleProximity = 5;
+constexpr int kSensorHandleLight = 6;
+constexpr int kSensorHandlePressure = 7;
+constexpr int kSensorHandleRelativeHumidity = 8;
+constexpr int kSensorHandleMagneticFieldUncalibrated = 9;
+constexpr int kSensorHandleGyroscopeFieldUncalibrated = 10;
+
+int getSensorNumber();
+bool isSensorHandleValid(int h);
+const SensorInfo* getSensorInfoByHandle(int h);
+const char* getQemuSensorNameByHandle(int h);
+
+}  // namespace goldfish
diff --git a/sensors/sensors_qemu.c b/sensors/sensors_qemu.c
deleted file mode 100644
index 5312260..0000000
--- a/sensors/sensors_qemu.c
+++ /dev/null
@@ -1,981 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* this implements a sensors hardware library for the Android emulator.
- * the following code should be built as a shared library that will be
- * placed into /system/lib/hw/sensors.goldfish.so
- *
- * it will be loaded by the code in hardware/libhardware/hardware.c
- * which is itself called from com_android_server_SensorService.cpp
- */
-
-
-/* we connect with the emulator through the "sensors" qemud service
- */
-#define  SENSORS_SERVICE_NAME "sensors"
-
-#define LOG_TAG "QemuSensors"
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <log/log.h>
-#include <cutils/sockets.h>
-#include <hardware/sensors.h>
-
-#if 0
-#define  D(...)  ALOGD(__VA_ARGS__)
-#else
-#define  D(...)  ((void)0)
-#endif
-
-#define  E(...)  ALOGE(__VA_ARGS__)
-
-#include "qemud.h"
-
-/** SENSOR IDS AND NAMES
- **/
-
-#define MAX_NUM_SENSORS 10
-
-#define SUPPORTED_SENSORS  ((1<<MAX_NUM_SENSORS)-1)
-
-#define  ID_BASE                        SENSORS_HANDLE_BASE
-#define  ID_ACCELERATION                (ID_BASE+0)
-#define  ID_GYROSCOPE                   (ID_BASE+1)
-#define  ID_MAGNETIC_FIELD              (ID_BASE+2)
-#define  ID_ORIENTATION                 (ID_BASE+3)
-#define  ID_TEMPERATURE                 (ID_BASE+4)
-#define  ID_PROXIMITY                   (ID_BASE+5)
-#define  ID_LIGHT                       (ID_BASE+6)
-#define  ID_PRESSURE                    (ID_BASE+7)
-#define  ID_HUMIDITY                    (ID_BASE+8)
-#define  ID_MAGNETIC_FIELD_UNCALIBRATED (ID_BASE+9)
-
-#define  SENSORS_ACCELERATION                 (1 << ID_ACCELERATION)
-#define  SENSORS_GYROSCOPE                    (1 << ID_GYROSCOPE)
-#define  SENSORS_MAGNETIC_FIELD               (1 << ID_MAGNETIC_FIELD)
-#define  SENSORS_ORIENTATION                  (1 << ID_ORIENTATION)
-#define  SENSORS_TEMPERATURE                  (1 << ID_TEMPERATURE)
-#define  SENSORS_PROXIMITY                    (1 << ID_PROXIMITY)
-#define  SENSORS_LIGHT                        (1 << ID_LIGHT)
-#define  SENSORS_PRESSURE                     (1 << ID_PRESSURE)
-#define  SENSORS_HUMIDITY                     (1 << ID_HUMIDITY)
-#define  SENSORS_MAGNETIC_FIELD_UNCALIBRATED  (1 << ID_MAGNETIC_FIELD_UNCALIBRATED)
-
-#define  ID_CHECK(x)  ((unsigned)((x) - ID_BASE) < MAX_NUM_SENSORS)
-
-#define  SENSORS_LIST  \
-    SENSOR_(ACCELERATION,"acceleration") \
-    SENSOR_(GYROSCOPE,"gyroscope") \
-    SENSOR_(MAGNETIC_FIELD,"magnetic-field") \
-    SENSOR_(ORIENTATION,"orientation") \
-    SENSOR_(TEMPERATURE,"temperature") \
-    SENSOR_(PROXIMITY,"proximity") \
-    SENSOR_(LIGHT, "light") \
-    SENSOR_(PRESSURE, "pressure") \
-    SENSOR_(HUMIDITY, "humidity") \
-    SENSOR_(MAGNETIC_FIELD_UNCALIBRATED,"magnetic-field-uncalibrated") \
-
-static const struct {
-    const char*  name;
-    int          id; } _sensorIds[MAX_NUM_SENSORS] =
-{
-#define SENSOR_(x,y)  { y, ID_##x },
-    SENSORS_LIST
-#undef  SENSOR_
-};
-
-static const char*
-_sensorIdToName( int  id )
-{
-    int  nn;
-    for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
-        if (id == _sensorIds[nn].id)
-            return _sensorIds[nn].name;
-    return "<UNKNOWN>";
-}
-
-/* return the current time in nanoseconds */
-static int64_t now_ns(void) {
-    struct timespec  ts;
-    clock_gettime(CLOCK_BOOTTIME, &ts);
-    return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
-}
-
-/** SENSORS POLL DEVICE
- **
- ** This one is used to read sensor data from the hardware.
- ** We implement this by simply reading the data from the
- ** emulator through the QEMUD channel.
- **/
-
-typedef struct SensorDevice {
-    struct sensors_poll_device_1  device;
-    sensors_event_t               sensors[MAX_NUM_SENSORS];
-    uint32_t                      pendingSensors;
-    int64_t                       timeStart;
-    int64_t                       timeOffset;
-    uint32_t                      active_sensors;
-    int                           fd;
-    int                           flush_count[MAX_NUM_SENSORS];
-    pthread_mutex_t               lock;
-} SensorDevice;
-
-/* Grab the file descriptor to the emulator's sensors service pipe.
- * This function returns a file descriptor on success, or -errno on
- * failure, and assumes the SensorDevice instance's lock is held.
- *
- * This is needed because set_delay(), poll() and activate() can be called
- * from different threads, and poll() is blocking.
- *
- * Note that the emulator's sensors service creates a new client for each
- * connection through qemud_channel_open(), where each client has its own
- * delay and set of activated sensors. This precludes calling
- * qemud_channel_open() on each request, because a typical emulated system
- * will do something like:
- *
- * 1) On a first thread, de-activate() all sensors first, then call poll(),
- *    which results in the thread blocking.
- *
- * 2) On a second thread, slightly later, call set_delay() then activate()
- *    to enable the acceleration sensor.
- *
- * The system expects this to unblock the first thread which will receive
- * new sensor events after the activate() call in 2).
- *
- * This cannot work if both threads don't use the same connection.
- *
- * TODO(digit): This protocol is brittle, implement another control channel
- *              for set_delay()/activate()/batch() when supporting HAL 1.3
- */
-static int sensor_device_get_fd_locked(SensorDevice* dev) {
-    /* Create connection to service on first call */
-    if (dev->fd < 0) {
-        dev->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
-        if (dev->fd < 0) {
-            int ret = -errno;
-            E("%s: Could not open connection to service: %s", __FUNCTION__,
-                strerror(-ret));
-            return ret;
-        }
-    }
-    return dev->fd;
-}
-
-/* Send a command to the sensors virtual device. |dev| is a device instance and
- * |cmd| is a zero-terminated command string. Return 0 on success, or -errno
- * on failure. */
-static int sensor_device_send_command_locked(SensorDevice* dev,
-                                             const char* cmd) {
-    int fd = sensor_device_get_fd_locked(dev);
-    if (fd < 0) {
-        return fd;
-    }
-
-    int ret = 0;
-    if (qemud_channel_send(fd, cmd, strlen(cmd)) < 0) {
-        ret = -errno;
-        E("%s(fd=%d): ERROR: %s", __FUNCTION__, fd, strerror(errno));
-    }
-    return ret;
-}
-
-/* Pick up one pending sensor event. On success, this returns the sensor
- * id, and sets |*event| accordingly. On failure, i.e. if there are no
- * pending events, return -EINVAL.
- *
- * Note: The device's lock must be acquired.
- */
-static int sensor_device_pick_pending_event_locked(SensorDevice* d,
-                                                   sensors_event_t*  event)
-{
-    uint32_t mask = SUPPORTED_SENSORS & d->pendingSensors;
-    if (mask) {
-        uint32_t i = 31 - __builtin_clz(mask);
-        d->pendingSensors &= ~(1U << i);
-        // Copy the structure
-        *event = d->sensors[i];
-
-        if (d->sensors[i].type == SENSOR_TYPE_META_DATA) {
-            if (d->flush_count[i] > 0) {
-                // Another 'flush' is queued after this one.
-                // Don't clear this event; just decrement the count.
-                (d->flush_count[i])--;
-                // And re-mark it as pending
-                d->pendingSensors |= (1U << i);
-            } else {
-                // We are done flushing
-                // sensor_device_poll_event_locked() will leave
-                // the meta-data in place until we have it.
-                // Set |type| to something other than META_DATA
-                // so sensor_device_poll_event_locked() can
-                // continue.
-                d->sensors[i].type = SENSOR_TYPE_META_DATA + 1;
-            }
-        } else {
-            event->sensor = i;
-            event->version = sizeof(*event);
-        }
-
-        D("%s: %d [%f, %f, %f]", __FUNCTION__,
-                i,
-                event->data[0],
-                event->data[1],
-                event->data[2]);
-        return i;
-    }
-    E("No sensor to return!!! pendingSensors=0x%08x", d->pendingSensors);
-    // we may end-up in a busy loop, slow things down, just in case.
-    usleep(1000);
-    return -EINVAL;
-}
-
-/* Block until new sensor events are reported by the emulator, or if a
- * 'wake' command is received through the service. On succes, return 0
- * and updates the |pendingEvents| and |sensors| fields of |dev|.
- * On failure, return -errno.
- *
- * Note: The device lock must be acquired when calling this function, and
- *       will still be held on return. However, the function releases the
- *       lock temporarily during the blocking wait.
- */
-static int sensor_device_poll_event_locked(SensorDevice* dev)
-{
-    D("%s: dev=%p", __FUNCTION__, dev);
-
-    int fd = sensor_device_get_fd_locked(dev);
-    if (fd < 0) {
-        E("%s: Could not get pipe channel: %s", __FUNCTION__, strerror(-fd));
-        return fd;
-    }
-
-    // Accumulate pending events into |events| and |new_sensors| mask
-    // until a 'sync' or 'wake' command is received. This also simplifies the
-    // code a bit.
-    uint32_t new_sensors = 0U;
-    sensors_event_t* events = dev->sensors;
-
-    int64_t event_time = -1;
-    int ret = 0;
-
-    int64_t guest_event_time = -1;
-    int has_guest_event_time = 0;
-
-
-    for (;;) {
-        /* Release the lock since we're going to block on recv() */
-        pthread_mutex_unlock(&dev->lock);
-
-        /* read the next event */
-        char buff[256];
-        int len = qemud_channel_recv(fd, buff, sizeof(buff) - 1U);
-        /* re-acquire the lock to modify the device state. */
-        pthread_mutex_lock(&dev->lock);
-
-        if (len < 0) {
-            ret = -errno;
-            E("%s(fd=%d): Could not receive event data len=%d, errno=%d: %s",
-              __FUNCTION__, fd, len, errno, strerror(errno));
-            break;
-        }
-        buff[len] = 0;
-        D("%s(fd=%d): received [%s]", __FUNCTION__, fd, buff);
-
-
-        /* "wake" is sent from the emulator to exit this loop. */
-        /* TODO(digit): Is it still needed? */
-        if (!strcmp((const char*)buff, "wake")) {
-            ret = 0x7FFFFFFF;
-            break;
-        }
-
-        float params[3];
-
-        // If the existing entry for this sensor is META_DATA,
-        // do not overwrite it. We can resume saving sensor
-        // values after that meta data has been received.
-
-        /* "acceleration:<x>:<y>:<z>" corresponds to an acceleration event */
-        if (sscanf(buff, "acceleration:%g:%g:%g", params+0, params+1, params+2)
-                == 3) {
-            new_sensors |= SENSORS_ACCELERATION;
-            if (events[ID_ACCELERATION].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_ACCELERATION].acceleration.x = params[0];
-            events[ID_ACCELERATION].acceleration.y = params[1];
-            events[ID_ACCELERATION].acceleration.z = params[2];
-            events[ID_ACCELERATION].type = SENSOR_TYPE_ACCELEROMETER;
-            continue;
-        }
-
-        /* "gyroscope:<x>:<y>:<z>" corresponds to a gyroscope event */
-        if (sscanf(buff, "gyroscope:%g:%g:%g", params+0, params+1, params+2)
-                == 3) {
-            new_sensors |= SENSORS_GYROSCOPE;
-            if (events[ID_GYROSCOPE].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_GYROSCOPE].gyro.x = params[0];
-            events[ID_GYROSCOPE].gyro.y = params[1];
-            events[ID_GYROSCOPE].gyro.z = params[2];
-            events[ID_GYROSCOPE].type = SENSOR_TYPE_GYROSCOPE;
-            continue;
-        }
-
-        /* "orientation:<azimuth>:<pitch>:<roll>" is sent when orientation
-         * changes */
-        if (sscanf(buff, "orientation:%g:%g:%g", params+0, params+1, params+2)
-                == 3) {
-            new_sensors |= SENSORS_ORIENTATION;
-            if (events[ID_ORIENTATION].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_ORIENTATION].orientation.azimuth = params[0];
-            events[ID_ORIENTATION].orientation.pitch   = params[1];
-            events[ID_ORIENTATION].orientation.roll    = params[2];
-            events[ID_ORIENTATION].orientation.status  =
-                    SENSOR_STATUS_ACCURACY_HIGH;
-            events[ID_ORIENTATION].type = SENSOR_TYPE_ORIENTATION;
-            continue;
-        }
-
-        /* "magnetic:<x>:<y>:<z>" is sent for the params of the magnetic
-         * field */
-        if (sscanf(buff, "magnetic:%g:%g:%g", params+0, params+1, params+2)
-                == 3) {
-            new_sensors |= SENSORS_MAGNETIC_FIELD;
-            if (events[ID_MAGNETIC_FIELD].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_MAGNETIC_FIELD].magnetic.x = params[0];
-            events[ID_MAGNETIC_FIELD].magnetic.y = params[1];
-            events[ID_MAGNETIC_FIELD].magnetic.z = params[2];
-            events[ID_MAGNETIC_FIELD].magnetic.status =
-                    SENSOR_STATUS_ACCURACY_HIGH;
-            events[ID_MAGNETIC_FIELD].type = SENSOR_TYPE_MAGNETIC_FIELD;
-            continue;
-        }
-
-        if (sscanf(buff, "magnetic-uncalibrated:%g:%g:%g", params+0, params+1, params+2)
-                == 3) {
-            new_sensors |= SENSORS_MAGNETIC_FIELD_UNCALIBRATED;
-            if (events[ID_MAGNETIC_FIELD_UNCALIBRATED].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_MAGNETIC_FIELD_UNCALIBRATED].magnetic.x = params[0];
-            events[ID_MAGNETIC_FIELD_UNCALIBRATED].magnetic.y = params[1];
-            events[ID_MAGNETIC_FIELD_UNCALIBRATED].magnetic.z = params[2];
-            events[ID_MAGNETIC_FIELD_UNCALIBRATED].magnetic.status =
-                    SENSOR_STATUS_ACCURACY_HIGH;
-            events[ID_MAGNETIC_FIELD_UNCALIBRATED].type = SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
-            continue;
-        }
-
-        /* "temperature:<celsius>" */
-        if (sscanf(buff, "temperature:%g", params+0) == 1) {
-            new_sensors |= SENSORS_TEMPERATURE;
-            if (events[ID_TEMPERATURE].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_TEMPERATURE].temperature = params[0];
-            events[ID_TEMPERATURE].type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
-            continue;
-        }
-
-        /* "proximity:<value>" */
-        if (sscanf(buff, "proximity:%g", params+0) == 1) {
-            new_sensors |= SENSORS_PROXIMITY;
-            if (events[ID_PROXIMITY].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_PROXIMITY].distance = params[0];
-            events[ID_PROXIMITY].type = SENSOR_TYPE_PROXIMITY;
-            continue;
-        }
-        /* "light:<lux>" */
-        if (sscanf(buff, "light:%g", params+0) == 1) {
-            new_sensors |= SENSORS_LIGHT;
-            if (events[ID_LIGHT].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_LIGHT].light = params[0];
-            events[ID_LIGHT].type = SENSOR_TYPE_LIGHT;
-            continue;
-        }
-
-        /* "pressure:<hpa>" */
-        if (sscanf(buff, "pressure:%g", params+0) == 1) {
-            new_sensors |= SENSORS_PRESSURE;
-            if (events[ID_PRESSURE].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_PRESSURE].pressure = params[0];
-            events[ID_PRESSURE].type = SENSOR_TYPE_PRESSURE;
-            continue;
-        }
-
-        /* "humidity:<percent>" */
-        if (sscanf(buff, "humidity:%g", params+0) == 1) {
-            new_sensors |= SENSORS_HUMIDITY;
-            if (events[ID_HUMIDITY].type == SENSOR_TYPE_META_DATA) continue;
-            events[ID_HUMIDITY].relative_humidity = params[0];
-            events[ID_HUMIDITY].type = SENSOR_TYPE_RELATIVE_HUMIDITY;
-            continue;
-        }
-
-        /* "guest-sync:<time>" is sent after a series of sensor events.
-         * where 'time' is expressed in micro-seconds and corresponds
-         * to the VM time when the real poll occured.
-         */
-        if (sscanf(buff, "guest-sync:%lld", &guest_event_time) == 1) {
-            has_guest_event_time = 1;
-            continue;
-        }
-
-        /* "sync:<time>" is sent after a series of sensor events.
-         * where 'time' is expressed in micro-seconds and corresponds
-         * to the VM time when the real poll occured.
-         */
-        if (sscanf(buff, "sync:%lld", &event_time) == 1) {
-            if (new_sensors) {
-                goto out;
-            }
-            D("huh ? sync without any sensor data ?");
-            continue;
-        }
-        D("huh ? unsupported command");
-    }
-out:
-    if (new_sensors) {
-        /* update the time of each new sensor event. */
-        dev->pendingSensors |= new_sensors;
-        int64_t t = (event_time < 0) ? 0 : event_time * 1000LL;
-
-        /* Use the time at the first "sync:" as the base for later
-         * time values.
-         * CTS tests require sensors to return an event timestamp (sync) that is
-         * strictly before the time of the event arrival. We don't actually have
-         * a time syncronization protocol here, and the only data point is the
-         * "sync:" timestamp - which is an emulator's timestamp of a clock that
-         * is synced with the guest clock, and it only the timestamp after all
-         * events were sent.
-         * To make it work, let's compare the calculated timestamp with current
-         * time and take the lower value - we don't believe in events from the
-         * future anyway.
-         */
-        const int64_t now = now_ns();
-
-        if (dev->timeStart == 0) {
-            dev->timeStart  = now;
-            dev->timeOffset = dev->timeStart - t;
-        }
-        t += dev->timeOffset;
-        if (t > now) {
-            t = now;
-        }
-
-        if (has_guest_event_time) {
-            if (guest_event_time > now) {
-                guest_event_time = now;
-            }
-        }
-
-        while (new_sensors) {
-            uint32_t i = 31 - __builtin_clz(new_sensors);
-            new_sensors &= ~(1U << i);
-            dev->sensors[i].timestamp =
-                    has_guest_event_time ? guest_event_time : t;
-        }
-    }
-    return ret;
-}
-
-/** SENSORS POLL DEVICE FUNCTIONS **/
-
-static int sensor_device_close(struct hw_device_t* dev0)
-{
-    SensorDevice* dev = (void*)dev0;
-    // Assume that there are no other threads blocked on poll()
-    if (dev->fd >= 0) {
-        close(dev->fd);
-        dev->fd = -1;
-    }
-    pthread_mutex_destroy(&dev->lock);
-    free(dev);
-    return 0;
-}
-
-/* Return an array of sensor data. This function blocks until there is sensor
- * related events to report. On success, it will write the events into the
- * |data| array, which contains |count| items. The function returns the number
- * of events written into the array, which shall never be greater than |count|.
- * On error, return -errno code.
- *
- * Note that according to the sensor HAL [1], it shall never return 0!
- *
- * [1] http://source.android.com/devices/sensors/hal-interface.html
- */
-static int sensor_device_poll(struct sensors_poll_device_t *dev0,
-                              sensors_event_t* data, int count)
-{
-    SensorDevice* dev = (void*)dev0;
-    D("%s: dev=%p data=%p count=%d ", __FUNCTION__, dev, data, count);
-
-    if (count <= 0) {
-        return -EINVAL;
-    }
-
-    int result = 0;
-    pthread_mutex_lock(&dev->lock);
-    if (!dev->pendingSensors) {
-        /* Block until there are pending events. Note that this releases
-         * the lock during the blocking call, then re-acquires it before
-         * returning. */
-        int ret = sensor_device_poll_event_locked(dev);
-        if (ret < 0) {
-            result = ret;
-            goto out;
-        }
-        if (!dev->pendingSensors) {
-            /* 'wake' event received before any sensor data. */
-            result = -EIO;
-            goto out;
-        }
-    }
-    /* Now read as many pending events as needed. */
-    int i;
-    for (i = 0; i < count; i++)  {
-        if (!dev->pendingSensors) {
-            break;
-        }
-        int ret = sensor_device_pick_pending_event_locked(dev, data);
-        if (ret < 0) {
-            if (!result) {
-                result = ret;
-            }
-            break;
-        }
-        data++;
-        result++;
-    }
-out:
-    pthread_mutex_unlock(&dev->lock);
-    D("%s: result=%d", __FUNCTION__, result);
-    return result;
-}
-
-static int sensor_device_activate(struct sensors_poll_device_t *dev0,
-                                  int handle,
-                                  int enabled)
-{
-    SensorDevice* dev = (void*)dev0;
-
-    D("%s: handle=%s (%d) enabled=%d", __FUNCTION__,
-        _sensorIdToName(handle), handle, enabled);
-
-    /* Sanity check */
-    if (!ID_CHECK(handle)) {
-        E("%s: bad handle ID", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    /* Exit early if sensor is already enabled/disabled. */
-    uint32_t mask = (1U << handle);
-    uint32_t sensors = enabled ? mask : 0;
-
-    pthread_mutex_lock(&dev->lock);
-
-    uint32_t active = dev->active_sensors;
-    uint32_t new_sensors = (active & ~mask) | (sensors & mask);
-    uint32_t changed = active ^ new_sensors;
-
-    int ret = 0;
-    if (changed) {
-        /* Send command to the emulator. */
-        char command[64];
-        snprintf(command,
-                 sizeof command,
-                 "set:%s:%d",
-                 _sensorIdToName(handle),
-                 enabled != 0);
-
-        ret = sensor_device_send_command_locked(dev, command);
-        if (ret < 0) {
-            E("%s: when sending command errno=%d: %s", __FUNCTION__, -ret,
-              strerror(-ret));
-        } else {
-            dev->active_sensors = new_sensors;
-        }
-    }
-    pthread_mutex_unlock(&dev->lock);
-    return ret;
-}
-
-static int sensor_device_default_flush(
-        struct sensors_poll_device_1* dev0,
-        int handle) {
-
-    SensorDevice* dev = (void*)dev0;
-
-    D("%s: handle=%s (%d)", __FUNCTION__,
-        _sensorIdToName(handle), handle);
-
-    /* Sanity check */
-    if (!ID_CHECK(handle)) {
-        E("%s: bad handle ID", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    pthread_mutex_lock(&dev->lock);
-    if ((dev->pendingSensors & (1U << handle)) &&
-        dev->sensors[handle].type == SENSOR_TYPE_META_DATA)
-    {
-        // A 'flush' operation is already pending. Just increment the count.
-        (dev->flush_count[handle])++;
-    } else {
-        dev->flush_count[handle] = 0;
-        dev->sensors[handle].version = META_DATA_VERSION;
-        dev->sensors[handle].type = SENSOR_TYPE_META_DATA;
-        dev->sensors[handle].sensor = 0;
-        dev->sensors[handle].timestamp = 0;
-        dev->sensors[handle].meta_data.sensor = handle;
-        dev->sensors[handle].meta_data.what = META_DATA_FLUSH_COMPLETE;
-        dev->pendingSensors |= (1U << handle);
-    }
-    pthread_mutex_unlock(&dev->lock);
-
-    return 0;
-}
-
-static int sensor_device_set_delay(struct sensors_poll_device_t *dev0,
-                                   int handle __unused,
-                                   int64_t ns)
-{
-    SensorDevice* dev = (void*)dev0;
-
-    int ms = (int)(ns / 1000000);
-    D("%s: dev=%p delay-ms=%d", __FUNCTION__, dev, ms);
-
-    char command[64];
-    snprintf(command, sizeof command, "set-delay:%d", ms);
-
-    pthread_mutex_lock(&dev->lock);
-    int ret = sensor_device_send_command_locked(dev, command);
-    pthread_mutex_unlock(&dev->lock);
-    if (ret < 0) {
-        E("%s: Could not send command: %s", __FUNCTION__, strerror(-ret));
-    }
-    return ret;
-}
-
-static int sensor_device_default_batch(
-     struct sensors_poll_device_1* dev,
-     int sensor_handle,
-     int flags,
-     int64_t sampling_period_ns,
-     int64_t max_report_latency_ns) {
-    (void)flags;
-    (void)max_report_latency_ns;
-    return sensor_device_set_delay(dev, sensor_handle, sampling_period_ns);
-}
-
-/** MODULE REGISTRATION SUPPORT
- **
- ** This is required so that hardware/libhardware/hardware.c
- ** will dlopen() this library appropriately.
- **/
-
-/*
- * the following is the list of all supported sensors.
- * this table is used to build sSensorList declared below
- * according to which hardware sensors are reported as
- * available from the emulator (see get_sensors_list below)
- *
- * note: numerical values for maxRange/resolution/power for
- *       all sensors but light, pressure and humidity were
- *       taken from the reference AK8976A implementation
- */
-static const struct sensor_t sSensorListInit[] = {
-        { .name       = "Goldfish 3-axis Accelerometer",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_ACCELERATION,
-          .type       = SENSOR_TYPE_ACCELEROMETER,
-          .maxRange   = 39.3f,
-          .resolution = 1.0f/4032.0f,
-          .power      = 3.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.accelerometer",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_CONTINUOUS_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish 3-axis Gyroscope",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_GYROSCOPE,
-          .type       = SENSOR_TYPE_GYROSCOPE,
-          .maxRange   = 16.46f,
-          .resolution = 1.0f/1000.0f,
-          .power      = 3.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .stringType = "android.sensor.gyroscope",
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish 3-axis Magnetic field sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_MAGNETIC_FIELD,
-          .type       = SENSOR_TYPE_MAGNETIC_FIELD,
-          .maxRange   = 2000.0f,
-          .resolution = 0.5f,
-          .power      = 6.7f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.magnetic_field",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_CONTINUOUS_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish Orientation sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_ORIENTATION,
-          .type       = SENSOR_TYPE_ORIENTATION,
-          .maxRange   = 360.0f,
-          .resolution = 1.0f,
-          .power      = 9.7f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.orientation",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_CONTINUOUS_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish Ambient Temperature sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_TEMPERATURE,
-          .type       = SENSOR_TYPE_AMBIENT_TEMPERATURE,
-          .maxRange   = 80.0f,
-          .resolution = 1.0f,
-          .power      = 0.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.ambient_temperature",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_ON_CHANGE_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish Proximity sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_PROXIMITY,
-          .type       = SENSOR_TYPE_PROXIMITY,
-          .maxRange   = 1.0f,
-          .resolution = 1.0f,
-          .power      = 20.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.proximity",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_WAKE_UP | SENSOR_FLAG_ON_CHANGE_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish Light sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_LIGHT,
-          .type       = SENSOR_TYPE_LIGHT,
-          .maxRange   = 40000.0f,
-          .resolution = 1.0f,
-          .power      = 20.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.light",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_ON_CHANGE_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish Pressure sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_PRESSURE,
-          .type       = SENSOR_TYPE_PRESSURE,
-          .maxRange   = 800.0f,
-          .resolution = 1.0f,
-          .power      = 20.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.pressure",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_CONTINUOUS_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish Humidity sensor",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_HUMIDITY,
-          .type       = SENSOR_TYPE_RELATIVE_HUMIDITY,
-          .maxRange   = 100.0f,
-          .resolution = 1.0f,
-          .power      = 20.0f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .fifoReservedEventCount = 0,
-          .fifoMaxEventCount =   0,
-          .stringType = "android.sensor.relative_humidity",
-          .requiredPermission = 0,
-          .flags = SENSOR_FLAG_ON_CHANGE_MODE,
-          .reserved   = {}
-        },
-
-        { .name       = "Goldfish 3-axis Magnetic field sensor (uncalibrated)",
-          .vendor     = "The Android Open Source Project",
-          .version    = 1,
-          .handle     = ID_MAGNETIC_FIELD_UNCALIBRATED,
-          .type       = SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
-          .maxRange   = 2000.0f,
-          .resolution = 0.5f,
-          .power      = 6.7f,
-          .minDelay   = 10000,
-          .maxDelay   = 500 * 1000,
-          .stringType = "android.sensor.magnetic_field_uncalibrated",
-          .reserved   = {}
-        },
-};
-
-static struct sensor_t  sSensorList[MAX_NUM_SENSORS];
-
-static int sensors__get_sensors_list(struct sensors_module_t* module __unused,
-        struct sensor_t const** list)
-{
-    int  fd = qemud_channel_open(SENSORS_SERVICE_NAME);
-    char buffer[12];
-    int  mask, nn, count;
-    int  ret = 0;
-
-    if (fd < 0) {
-        E("%s: no qemud connection", __FUNCTION__);
-        goto out;
-    }
-    ret = qemud_channel_send(fd, "list-sensors", -1);
-    if (ret < 0) {
-        E("%s: could not query sensor list: %s", __FUNCTION__,
-          strerror(errno));
-        goto out;
-    }
-    ret = qemud_channel_recv(fd, buffer, sizeof buffer-1);
-    if (ret < 0) {
-        E("%s: could not receive sensor list: %s", __FUNCTION__,
-          strerror(errno));
-        goto out;
-    }
-    buffer[ret] = 0;
-
-    /* the result is a integer used as a mask for available sensors */
-    mask  = atoi(buffer);
-    count = 0;
-    for (nn = 0; nn < MAX_NUM_SENSORS; nn++) {
-        if (((1 << nn) & mask) == 0)
-            continue;
-        sSensorList[count++] = sSensorListInit[nn];
-    }
-    D("%s: returned %d sensors (mask=%d)", __FUNCTION__, count, mask);
-    *list = sSensorList;
-
-    ret = count;
-out:
-    if (fd >= 0) {
-        close(fd);
-    }
-    return ret;
-}
-
-
-static int
-open_sensors(const struct hw_module_t* module,
-             const char*               name,
-             struct hw_device_t*      *device)
-{
-    int  status = -EINVAL;
-
-    D("%s: name=%s", __FUNCTION__, name);
-
-    if (!strcmp(name, SENSORS_HARDWARE_POLL)) {
-        SensorDevice *dev = malloc(sizeof(*dev));
-
-        memset(dev, 0, sizeof(*dev));
-
-        dev->device.common.tag     = HARDWARE_DEVICE_TAG;
-        dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
-        dev->device.common.module  = (struct hw_module_t*) module;
-        dev->device.common.close   = sensor_device_close;
-        dev->device.poll           = sensor_device_poll;
-        dev->device.activate       = sensor_device_activate;
-        dev->device.setDelay       = sensor_device_set_delay;
-
-        // (dev->sensors[i].type == SENSOR_TYPE_META_DATA) is
-        // sticky. Don't start off with that setting.
-        for (int idx = 0; idx < MAX_NUM_SENSORS; idx++) {
-            dev->sensors[idx].type = SENSOR_TYPE_META_DATA + 1;
-            dev->flush_count[idx] = 0;
-        }
-
-        // Version 1.3-specific functions
-        dev->device.batch       = sensor_device_default_batch;
-        dev->device.flush       = sensor_device_default_flush;
-
-        dev->fd = -1;
-        pthread_mutex_init(&dev->lock, NULL);
-
-        int64_t now = now_ns();
-        char command[64];
-        sprintf(command, "time:%lld", now);
-        sensor_device_send_command_locked(dev, command);
-
-        *device = &dev->device.common;
-        status  = 0;
-    }
-    return status;
-}
-
-
-static struct hw_module_methods_t sensors_module_methods = {
-    .open = open_sensors
-};
-
-struct sensors_module_t HAL_MODULE_INFO_SYM = {
-    .common = {
-        .tag = HARDWARE_MODULE_TAG,
-        .version_major = 1,
-        .version_minor = 3,
-        .id = SENSORS_HARDWARE_MODULE_ID,
-        .name = "Goldfish SENSORS Module",
-        .author = "The Android Open Source Project",
-        .methods = &sensors_module_methods,
-    },
-    .get_sensors_list = sensors__get_sensors_list
-};
diff --git a/sensors/util.cpp b/sensors/util.cpp
new file mode 100644
index 0000000..034ecff
--- /dev/null
+++ b/sensors/util.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/macros.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include "util.h"
+
+namespace goldfish {
+
+int qemu_pipe_read_fully(int pipe, void* buffer, int len) {
+    char* p = (char*)buffer;
+    while (len > 0) {
+      int n = TEMP_FAILURE_RETRY(read(pipe, p, len));
+      if (n < 0) return n;
+      p += n;
+      len -= n;
+    }
+    return 0;
+}
+
+int qemu_pipe_write_fully(int pipe, const void* buffer, int len) {
+    const char* p = (const char*)buffer;
+    while (len > 0) {
+      int n = TEMP_FAILURE_RETRY(write(pipe, p, len));
+      if (n < 0) return n;
+      p += n;
+      len -= n;
+    }
+    return 0;
+}
+
+int qemu_pipe_open_ns(const char* ns, const char* pipeName, const int flags) {
+    int fd = TEMP_FAILURE_RETRY(open("/dev/goldfish_pipe", flags));
+    if (fd < 0) {
+        return -1;
+    }
+
+    char buff[64];
+
+    int len = snprintf(buff, sizeof(buff), "pipe:%s:%s", ns, pipeName);
+    if (qemu_pipe_write_fully(fd, buff, len + 1)) {
+        close(fd);
+        return -1;
+    }
+
+    return fd;
+}
+
+int qemud_channel_open(const char* name) {
+    return qemu_pipe_open_ns("qemud", name, O_RDWR);
+}
+
+int qemud_channel_send(int pipe, const void* msg, int msglen)
+{
+    char  header[5];
+
+    if (msglen < 0)
+        msglen = strlen((const char*)msg);
+
+    if (msglen == 0)
+        return 0;
+
+    snprintf(header, sizeof(header), "%04x", msglen);
+    if (qemu_pipe_write_fully(pipe, header, 4)) {
+        return -1;
+    }
+
+    if (qemu_pipe_write_fully(pipe, msg, msglen)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int qemud_channel_recv(int pipe, void*  msg, int  msgsize)
+{
+    char  header[5];
+    int   size;
+
+    if (qemu_pipe_read_fully(pipe, header, 4)) {
+        return -1;
+    }
+    header[4] = 0;
+
+    if (sscanf(header, "%04x", &size) != 1) {
+        return -1;
+    }
+
+    if (size > msgsize)
+        return -1;
+
+    if (qemu_pipe_read_fully(pipe, msg, size)) {
+        return -1;
+    }
+
+    return size;
+}
+
+}  // namespace goldfish
diff --git a/sensors/util.h b/sensors/util.h
new file mode 100644
index 0000000..30dc772
--- /dev/null
+++ b/sensors/util.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace goldfish {
+
+int qemu_pipe_open_ns(const char* ns, const char* pipeName, int flags);
+int qemu_pipe_read_fully(int pipe, void* buffer, int len);
+int qemu_pipe_write_fully(int pipe, const void* buffer, int len);
+
+int qemud_channel_open(const char* name);
+int qemud_channel_send(int pipe, const void* msg, int msglen);
+int qemud_channel_recv(int pipe, void*  msg, int msgsize);
+
+}  // namespace goldfish
diff --git a/vendor.mk b/vendor.mk
index 0008c85..80fdf94 100644
--- a/vendor.mk
+++ b/vendor.mk
@@ -123,10 +123,14 @@
 
 ifneq ($(EMULATOR_VENDOR_NO_SENSORS),true)
 PRODUCT_PACKAGES += \
-    android.hardware.sensors@1.0-impl \
-    android.hardware.sensors@1.0-service \
-    sensors.ranchu
-DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.sensors.xml
+    android.hardware.sensors@2.0-service.multihal \
+    android.hardware.sensors@2.0-impl.ranchu
+# TODO(rkir):
+# add a soong namespace and move this into a.h.sensors@2.0-impl.ranchu
+# as prebuilt_etc. For now soong_namespace causes a build break because the fw
+# refers to our wifi HAL in random places.
+PRODUCT_COPY_FILES += \
+    device/generic/goldfish/sensors/hals.conf:$(TARGET_COPY_OUT_VENDOR)/etc/sensors/hals.conf
 endif
 
 PRODUCT_PACKAGES += \