Add AIDL sensorservice implementation

Intended to be 1:1 functionality with the HIDL implementation.

Test: atest VtsHalSensorManagerTargetTest
Bug: 205764765

Change-Id: I7a30a7c119c6f48432cbefbaaebc7ad7dfc4a01e
diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp
new file mode 100644
index 0000000..bbf49da
--- /dev/null
+++ b/services/sensorservice/aidl/Android.bp
@@ -0,0 +1,43 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+    name: "libsensorserviceaidl",
+    srcs: [
+        "EventQueue.cpp",
+        "DirectReportChannel.cpp",
+        "SensorManager.cpp",
+        "utils.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    header_libs: ["jni_headers"],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libcutils",
+        "libbinder_ndk",
+        "libsensor",
+        "android.frameworks.sensorservice-V1-ndk",
+        "android.hardware.sensors-V1-ndk",
+    ],
+    export_include_dirs: [
+        "include/",
+    ],
+    static_libs: [
+        "android.hardware.sensors-V1-convert",
+    ],
+
+    export_header_lib_headers: ["jni_headers"],
+    local_include_dirs: [
+        "include/sensorserviceaidl/",
+    ],
+}
diff --git a/services/sensorservice/aidl/DirectReportChannel.cpp b/services/sensorservice/aidl/DirectReportChannel.cpp
new file mode 100644
index 0000000..cab53c1
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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 "DirectReportChannel.h"
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+DirectReportChannel::DirectReportChannel(::android::SensorManager& manager, int channelId)
+      : mManager(manager), mId(channelId) {}
+
+DirectReportChannel::~DirectReportChannel() {
+    mManager.destroyDirectChannel(mId);
+}
+
+ndk::ScopedAStatus DirectReportChannel::configure(
+        int32_t sensorHandle, ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+        int32_t* _aidl_return) {
+    int token = mManager.configureDirectChannel(mId, sensorHandle, static_cast<int>(rate));
+    if (token <= 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(token);
+    }
+    *_aidl_return = token;
+    return ndk::ScopedAStatus::ok();
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/DirectReportChannel.h b/services/sensorservice/aidl/DirectReportChannel.h
new file mode 100644
index 0000000..d9ea73d
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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 <aidl/android/frameworks/sensorservice/BnDirectReportChannel.h>
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class DirectReportChannel final
+      : public ::aidl::android::frameworks::sensorservice::BnDirectReportChannel {
+public:
+    DirectReportChannel(::android::SensorManager& manager, int channelId);
+    ~DirectReportChannel();
+
+    ndk::ScopedAStatus configure(int32_t sensorHandle,
+                                 ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+                                 int32_t* _aidl_return) override;
+
+private:
+    ::android::SensorManager& mManager;
+    const int mId;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.cpp b/services/sensorservice/aidl/EventQueue.cpp
new file mode 100644
index 0000000..d4e8906
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 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 "EventQueue.h"
+#include "utils.h"
+
+#include <android-base/logging.h>
+#include <utils/Looper.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::hardware::sensors::Event;
+
+class EventQueueLooperCallback : public ::android::LooperCallback {
+public:
+    EventQueueLooperCallback(sp<::android::SensorEventQueue> queue,
+                             std::shared_ptr<IEventQueueCallback> callback)
+          : mQueue(queue), mCallback(callback) {}
+
+    int handleEvent(__unused int fd, __unused int events, __unused void* data) {
+        ASensorEvent event;
+        ssize_t actual;
+
+        auto internalQueue = mQueue.promote();
+        if (internalQueue == nullptr) {
+            return 1;
+        }
+
+        while ((actual = internalQueue->read(&event, 1)) > 0) {
+            internalQueue->sendAck(&event, actual);
+            ndk::ScopedAStatus ret = mCallback->onEvent(convertEvent(event));
+            if (!ret.isOk()) {
+                LOG(ERROR) << "Failed to envoke EventQueueCallback: " << ret;
+            }
+        }
+
+        return 1; // continue to receive callbacks
+    }
+
+private:
+    wp<::android::SensorEventQueue> mQueue;
+    std::shared_ptr<IEventQueueCallback> mCallback;
+};
+
+EventQueue::EventQueue(std::shared_ptr<IEventQueueCallback> callback, sp<::android::Looper> looper,
+                       sp<::android::SensorEventQueue> internalQueue)
+      : mLooper(looper), mInternalQueue(internalQueue) {
+    mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
+                   new EventQueueLooperCallback(internalQueue, callback), nullptr);
+}
+
+// FIXME why was this on onLastStrongRef instead of dtor?
+EventQueue::~EventQueue() {
+    mLooper->removeFd(mInternalQueue->getFd());
+}
+
+ndk::ScopedAStatus EventQueue::enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+                                            int64_t in_maxBatchReportLatencyUs) {
+    return convertResult(mInternalQueue->enableSensor(in_sensorHandle, in_samplingPeriodUs,
+                                                      in_maxBatchReportLatencyUs, 0));
+}
+
+ndk::ScopedAStatus EventQueue::disableSensor(int32_t in_sensorHandle) {
+    return convertResult(mInternalQueue->disableSensor(in_sensorHandle));
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.h b/services/sensorservice/aidl/EventQueue.h
new file mode 100644
index 0000000..0ae1eba
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 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 "SensorManagerAidl.h"
+
+#include <aidl/android/frameworks/sensorservice/BnEventQueue.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+struct EventQueue final : public aidl::android::frameworks::sensorservice::BnEventQueue {
+    EventQueue(
+            std::shared_ptr<aidl::android::frameworks::sensorservice::IEventQueueCallback> callback,
+            sp<::android::Looper> looper, sp<::android::SensorEventQueue> internalQueue);
+    ~EventQueue();
+
+    ndk::ScopedAStatus enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+                                    int64_t in_maxBatchReportLatencyUs) override;
+    ndk::ScopedAStatus disableSensor(int32_t sensorHandle) override;
+
+private:
+    friend class EventQueueLooperCallback;
+    sp<::android::Looper> mLooper;
+    sp<::android::SensorEventQueue> mInternalQueue;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp
new file mode 100644
index 0000000..6d8d574
--- /dev/null
+++ b/services/sensorservice/aidl/SensorManager.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+// LOG_TAG defined via build flag.
+#ifndef LOG_TAG
+#define LOG_TAG "AidlSensorManager"
+#endif
+
+#include "DirectReportChannel.h"
+#include "EventQueue.h"
+#include "SensorManagerAidl.h"
+#include "utils.h"
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
+#include <sched.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IDirectReportChannel;
+using ::aidl::android::frameworks::sensorservice::IEventQueue;
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::frameworks::sensorservice::ISensorManager;
+using ::aidl::android::hardware::common::Ashmem;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::aidl::android::hardware::sensors::SensorType;
+using ::android::frameworks::sensorservice::implementation::SensorManagerAidl;
+
+static const char* POLL_THREAD_NAME = "aidl_ssvc_poll";
+
+SensorManagerAidl::SensorManagerAidl(JavaVM* vm)
+      : mLooper(new Looper(false)), mStopThread(true), mJavaVm(vm) {}
+SensorManagerAidl::~SensorManagerAidl() {
+    // Stops pollAll inside the thread.
+    std::lock_guard<std::mutex> lock(mThreadMutex);
+
+    mStopThread = true;
+    if (mLooper != nullptr) {
+        mLooper->wake();
+    }
+    if (mPollThread.joinable()) {
+        mPollThread.join();
+    }
+}
+
+ndk::ScopedAStatus createDirectChannel(::android::SensorManager& manager, size_t size, int type,
+                                       const native_handle_t* handle,
+                                       std::shared_ptr<IDirectReportChannel>* chan) {
+    int channelId = manager.createDirectChannel(size, type, handle);
+    if (channelId < 0) {
+        return convertResult(channelId);
+    }
+    if (channelId == 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+    *chan = ndk::SharedRefBase::make<DirectReportChannel>(manager, channelId);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createAshmemDirectChannel(
+        const Ashmem& in_mem, int64_t in_size,
+        std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+    if (in_size > in_mem.size || in_size < ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+    }
+    native_handle_t* handle = native_handle_create(1, 0);
+    handle->data[0] = dup(in_mem.fd.get());
+
+    auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_ASHMEM,
+                                      handle, _aidl_return);
+    int result = native_handle_close(handle);
+    CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+    result = native_handle_delete(handle);
+    CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+    return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createGrallocDirectChannel(
+        const ndk::ScopedFileDescriptor& in_mem, int64_t in_size,
+        std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+    native_handle_t* handle = native_handle_create(1, 0);
+    handle->data[0] = dup(in_mem.get());
+
+    auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_GRALLOC,
+                                      handle, _aidl_return);
+    int result = native_handle_close(handle);
+    CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+    result = native_handle_delete(handle);
+    CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+    return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createEventQueue(
+        const std::shared_ptr<IEventQueueCallback>& in_callback,
+        std::shared_ptr<IEventQueue>* _aidl_return) {
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+    }
+
+    sp<::android::Looper> looper = getLooper();
+    if (looper == nullptr) {
+        LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue cannot initialize looper";
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+
+    String8 package(String8::format("aidl_client_pid_%d", AIBinder_getCallingPid()));
+    sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package);
+    if (internalQueue == nullptr) {
+        LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue returns nullptr.";
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+
+    *_aidl_return = ndk::SharedRefBase::make<EventQueue>(in_callback, looper, internalQueue);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+SensorInfo convertSensor(Sensor src) {
+    SensorInfo dst;
+    dst.sensorHandle = src.getHandle();
+    dst.name = src.getName();
+    dst.vendor = src.getVendor();
+    dst.version = src.getVersion();
+    dst.type = static_cast<SensorType>(src.getType());
+    dst.typeAsString = src.getStringType();
+    // maxRange uses maxValue because ::android::Sensor wraps the
+    // internal sensor_t in this way.
+    dst.maxRange = src.getMaxValue();
+    dst.resolution = src.getResolution();
+    dst.power = src.getPowerUsage();
+    dst.minDelayUs = src.getMinDelay();
+    dst.fifoReservedEventCount = src.getFifoReservedEventCount();
+    dst.fifoMaxEventCount = src.getFifoMaxEventCount();
+    dst.requiredPermission = src.getRequiredPermission();
+    dst.maxDelayUs = src.getMaxDelay();
+    dst.flags = src.getFlags();
+    return dst;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getDefaultSensor(SensorType in_type,
+                                                       SensorInfo* _aidl_return) {
+    ::android::Sensor const* sensor =
+            getInternalManager().getDefaultSensor(static_cast<int>(in_type));
+    if (!sensor) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_NOT_EXIST);
+    }
+    *_aidl_return = convertSensor(*sensor);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector<SensorInfo>* _aidl_return) {
+    Sensor const* const* list;
+    _aidl_return->clear();
+    ssize_t count = getInternalManager().getSensorList(&list);
+    if (count < 0 || list == nullptr) {
+        LOG(ERROR) << "SensorMAanger::getSensorList failed with count: " << count;
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+    _aidl_return->reserve(static_cast<size_t>(count));
+    for (ssize_t i = 0; i < count; ++i) {
+        _aidl_return->push_back(convertSensor(*list[i]));
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+::android::SensorManager& SensorManagerAidl::getInternalManager() {
+    std::lock_guard<std::mutex> lock(mInternalManagerMutex);
+    if (mInternalManager == nullptr) {
+        mInternalManager = &::android::SensorManager::getInstanceForPackage(
+                String16(ISensorManager::descriptor));
+    }
+    return *mInternalManager;
+}
+
+/* One global looper for all event queues created from this SensorManager. */
+sp<Looper> SensorManagerAidl::getLooper() {
+    std::lock_guard<std::mutex> lock(mThreadMutex);
+
+    if (!mPollThread.joinable()) {
+        // if thread not initialized, start thread
+        mStopThread = false;
+        std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
+            struct sched_param p = {0};
+            p.sched_priority = 10;
+            if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) {
+                LOG(ERROR) << "Could not use SCHED_FIFO for looper thread: " << strerror(errno);
+            }
+
+            // set looper
+            Looper::setForThread(looper);
+
+            // Attach the thread to JavaVM so that pollAll do not crash if the thread
+            // eventually calls into Java.
+            JavaVMAttachArgs args{.version = JNI_VERSION_1_2,
+                                  .name = POLL_THREAD_NAME,
+                                  .group = nullptr};
+            JNIEnv* env;
+            if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+                LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
+            }
+
+            LOG(INFO) << POLL_THREAD_NAME << " started.";
+            for (;;) {
+                int pollResult = looper->pollAll(-1 /* timeout */);
+                if (pollResult == Looper::POLL_WAKE) {
+                    if (stopThread == true) {
+                        LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+                        break;
+                    } else {
+                        LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+                    }
+                } else {
+                    LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+                               << pollResult;
+                    break;
+                }
+            }
+
+            if (javaVm->DetachCurrentThread() != JNI_OK) {
+                LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
+            }
+
+            LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+        }};
+        mPollThread = std::move(pollThread);
+    }
+    return mLooper;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
new file mode 100644
index 0000000..c77ee88
--- /dev/null
+++ b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 <aidl/android/frameworks/sensorservice/BnSensorManager.h>
+#include <jni.h>
+#include <sensor/SensorManager.h>
+#include <utils/Looper.h>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class SensorManagerAidl : public ::aidl::android::frameworks::sensorservice::BnSensorManager {
+public:
+    explicit SensorManagerAidl(JavaVM* vm);
+    ~SensorManagerAidl();
+
+    ::ndk::ScopedAStatus createAshmemDirectChannel(
+            const ::aidl::android::hardware::common::Ashmem& in_mem, int64_t in_size,
+            std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+                    _aidl_return) override;
+    ::ndk::ScopedAStatus createEventQueue(
+            const std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueueCallback>&
+                    in_callback,
+            std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueue>* _aidl_return)
+            override;
+    ::ndk::ScopedAStatus createGrallocDirectChannel(
+            const ::ndk::ScopedFileDescriptor& in_buffer, int64_t in_size,
+            std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+                    _aidl_return) override;
+    ::ndk::ScopedAStatus getDefaultSensor(
+            ::aidl::android::hardware::sensors::SensorType in_type,
+            ::aidl::android::hardware::sensors::SensorInfo* _aidl_return) override;
+    ::ndk::ScopedAStatus getSensorList(
+            std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+
+private:
+    // Block until ::android::SensorManager is initialized.
+    ::android::SensorManager& getInternalManager();
+    sp<Looper> getLooper();
+
+    std::mutex mInternalManagerMutex;
+    ::android::SensorManager* mInternalManager = nullptr; // does not own
+    sp<Looper> mLooper;
+
+    volatile bool mStopThread;
+    std::mutex mThreadMutex; // protects mPollThread
+    std::thread mPollThread;
+
+    JavaVM* mJavaVm;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.cpp b/services/sensorservice/aidl/utils.cpp
new file mode 100644
index 0000000..26bcdc5
--- /dev/null
+++ b/services/sensorservice/aidl/utils.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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 "utils.h"
+
+#include <aidl/android/frameworks/sensorservice/ISensorManager.h>
+#include <aidl/sensors/convert.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+ndk::ScopedAStatus convertResult(status_t src) {
+    using ::aidl::android::frameworks::sensorservice::ISensorManager;
+
+    int err = 0;
+    switch (src) {
+        case OK:
+            return ndk::ScopedAStatus::ok();
+        case NAME_NOT_FOUND:
+            err = ISensorManager::RESULT_NOT_EXIST;
+            break;
+        case NO_MEMORY:
+            err = ISensorManager::RESULT_NO_MEMORY;
+            break;
+        case NO_INIT:
+            err = ISensorManager::RESULT_NO_INIT;
+            break;
+        case PERMISSION_DENIED:
+            err = ISensorManager::RESULT_PERMISSION_DENIED;
+            break;
+        case BAD_VALUE:
+            err = ISensorManager::RESULT_BAD_VALUE;
+            break;
+        case INVALID_OPERATION:
+            err = ISensorManager::RESULT_INVALID_OPERATION;
+            break;
+        default:
+            err = ISensorManager::RESULT_UNKNOWN_ERROR;
+    }
+    return ndk::ScopedAStatus::fromServiceSpecificError(err);
+}
+
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& src) {
+    ::aidl::android::hardware::sensors::Event dst;
+    ::android::hardware::sensors::implementation::
+            convertFromSensorEvent(reinterpret_cast<const sensors_event_t&>(src), &dst);
+    return dst;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.h b/services/sensorservice/aidl/utils.h
new file mode 100644
index 0000000..06ba59e
--- /dev/null
+++ b/services/sensorservice/aidl/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 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 <aidl/android/hardware/sensors/Event.h>
+#include <sensor/Sensor.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+::ndk::ScopedAStatus convertResult(status_t status);
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& event);
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android