(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 += \