Add native test for sensor direct report NDK API
Add native test for the following NDK functions:
* ASensorManager_configureDirectReport
* ASensorManager_createAshmemDirectChannel
* ASensorManager_destroyDirectChannel
* ASensor_getHighestDirectReportRateLevel
* ASensor_isDirectChannelTypeSupported
Also tested the following NDK API as well as passing created shared
memory across process boundary (app to service).
* ASharedMemory_create
* ASharedMemory_getSize
Test: cts-tradefed run cts --module CtsSensorTestCases \
--test android.hardware.cts.SensorNativeTest
Change-Id: Ie225c42dda34cda3fcaf5ca405d82efecbdfaa80
diff --git a/tests/sensor/Android.mk b/tests/sensor/Android.mk
index d3e7ce2..a231c3c 100644
--- a/tests/sensor/Android.mk
+++ b/tests/sensor/Android.mk
@@ -14,7 +14,9 @@
LOCAL_PATH:= $(call my-dir)
+#
# Reusable Sensor test classes and helpers
+#
include $(CLEAR_VARS)
LOCAL_MODULE := cts-sensors-tests
@@ -30,10 +32,38 @@
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
include $(BUILD_STATIC_JAVA_LIBRARY)
+#
+# JNI components for testing NDK
+#
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcts-sensors-ndk-jni
+
+LOCAL_CFLAGS += -Werror -Wall -Wextra
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ jni/SensorTest.cpp \
+ jni/android_view_cts_SensorNativeTest.cpp \
+ jni/nativeTestHelper.cpp \
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := libandroid liblog
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_NDK_STL_VARIANT := c++_shared
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
# CtsSensorTestCases package
+#
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
@@ -47,9 +77,14 @@
ctstestrunner \
cts-sensors-tests \
+LOCAL_JNI_SHARED_LIBRARIES := libcts-sensors-ndk-jni
+
LOCAL_PACKAGE_NAME := CtsSensorTestCases
LOCAL_SDK_VERSION := current
+
LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_NDK_STL_VARIANT := c++_shared
+
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/sensor/jni/SensorTest.cpp b/tests/sensor/jni/SensorTest.cpp
new file mode 100644
index 0000000..3593047
--- /dev/null
+++ b/tests/sensor/jni/SensorTest.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2017 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 "SensorTest.h"
+#include <errno.h>
+
+namespace android {
+namespace SensorTest {
+
+// SensorTest container class
+bool SensorTest::SetUp() {
+ if (mManager == nullptr) {
+ mManager.reset(
+ TestSensorManager::getInstanceForPackage("android.hardware.cts.SensorNativeTest"));
+ }
+ return mManager == nullptr;
+}
+
+void SensorTest::TearDown() {
+ if (mManager == nullptr) {
+ mManager.reset(nullptr);
+ }
+}
+
+void SensorTest::testInitialized(JNIEnv *env) {
+ ASSERT_TRUE(mManager->isValid());
+}
+
+TestSensorManager::TestSensorManager(const char *package) {
+ mManager = ASensorManager_getInstanceForPackage(package);
+}
+
+TestSensorManager::~TestSensorManager() {
+ for (int channel : mSensorDirectChannel) {
+ destroyDirectChannel(channel);
+ }
+ mSensorDirectChannel.clear();
+}
+
+TestSensorManager * TestSensorManager::getInstanceForPackage(const char *package) {
+ return new TestSensorManager(package);
+}
+
+TestSensor TestSensorManager::getDefaultSensor(int type) {
+ return TestSensor(ASensorManager_getDefaultSensor(mManager, type));
+}
+
+int TestSensorManager::createDirectChannel(const TestSharedMemory &mem) {
+ if (!isValid()) {
+ return -EINVAL;
+ }
+ switch (mem.getType()) {
+ case ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY:
+ return createSharedMemoryDirectChannel(
+ mem.getSharedMemoryFd(), mem.getSize());
+ case ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER:
+ return createHardwareBufferDirectChannel(
+ mem.getHardwareBuffer(), mem.getSize());
+ default:
+ return -1;
+ }
+}
+
+int TestSensorManager::createSharedMemoryDirectChannel(int fd, size_t size) {
+ int ret = ASensorManager_createSharedMemoryDirectChannel(mManager, fd, size);
+ if (ret > 0) {
+ mSensorDirectChannel.insert(ret);
+ }
+ return ret;
+}
+
+int TestSensorManager::createHardwareBufferDirectChannel(
+ AHardwareBuffer const *buffer, size_t size) {
+ int ret = ASensorManager_createHardwareBufferDirectChannel(mManager, buffer, size);
+ if (ret > 0) {
+ mSensorDirectChannel.insert(ret);
+ }
+ return ret;
+}
+
+void TestSensorManager::destroyDirectChannel(int channel) {
+ if (!isValid()) {
+ return;
+ }
+ ASensorManager_destroyDirectChannel(mManager, channel);
+ mSensorDirectChannel.erase(channel);
+ return;
+}
+
+int TestSensorManager::configureDirectReport(TestSensor sensor, int channel, int rate) {
+ if (!isValid()) {
+ return -EINVAL;
+ }
+ return ASensorManager_configureDirectReport(mManager, sensor, channel, rate);
+}
+
+char * TestSharedMemory::getBuffer() const {
+ return mBuffer;
+}
+
+std::vector<ASensorEvent> TestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
+ constexpr size_t kEventSize = sizeof(ASensorEvent);
+ constexpr size_t kOffsetSize = offsetof(ASensorEvent, version);
+ constexpr size_t kOffsetAtomicCounter = offsetof(ASensorEvent, reserved0);
+
+ std::vector<ASensorEvent> events;
+ while (offset + kEventSize <= mSize) {
+ int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter);
+ if (atomicCounter <= lastCounter) {
+ break;
+ }
+
+ int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize);
+ if (size != kEventSize) {
+ // unknown error, events parsed may be wrong, remove all
+ events.clear();
+ break;
+ }
+
+ events.push_back(*reinterpret_cast<ASensorEvent *>(mBuffer + offset));
+ lastCounter = atomicCounter;
+ offset += kEventSize;
+ }
+
+ return events;
+}
+
+TestSharedMemory::TestSharedMemory(int type, size_t size)
+ : mType(type), mSize(0), mBuffer(nullptr),
+ mSharedMemoryFd(-1), mHardwareBuffer(nullptr) {
+ bool success = false;
+ switch(type) {
+ case ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY: {
+ mSharedMemoryFd = ASharedMemory_create("TestSharedMemory", size);
+ if (mSharedMemoryFd < 0
+ || ASharedMemory_getSize(mSharedMemoryFd) != size) {
+ break;
+ }
+
+ mSize = size;
+ mBuffer = reinterpret_cast<char *>(::mmap(
+ nullptr, mSize, PROT_READ | PROT_WRITE,
+ MAP_SHARED, mSharedMemoryFd, 0));
+
+ if (mBuffer == MAP_FAILED) {
+ mBuffer = nullptr;
+ break;
+ }
+ success = true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (!success) {
+ release();
+ }
+}
+
+TestSharedMemory::~TestSharedMemory() {
+ release();
+}
+
+void TestSharedMemory::release() {
+ switch(mType) {
+ case ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY: {
+ if (mBuffer != nullptr) {
+ ::munmap(mBuffer, mSize);
+ mBuffer = nullptr;
+ }
+ if (mSharedMemoryFd > 0) {
+ ::close(mSharedMemoryFd);
+ mSharedMemoryFd = -1;
+ }
+ mSize = 0;
+ break;
+ }
+ default:
+ break;
+ }
+ if (mSharedMemoryFd > 0 || mSize != 0 || mBuffer != nullptr) {
+ ALOGE("TestSharedMemory %p not properly destructed: "
+ "type %d, shared_memory_fd %d, hardware_buffer %p, size %zu, buffer %p",
+ this, static_cast<int>(mType), mSharedMemoryFd, mHardwareBuffer, mSize, mBuffer);
+ }
+}
+
+TestSharedMemory* TestSharedMemory::create(int type, size_t size) {
+ constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M
+ if (size == 0 || size >= kMaxSize) {
+ return nullptr;
+ }
+
+ auto m = new TestSharedMemory(type, size);
+ if (m->mSize != size || m->mBuffer == nullptr) {
+ delete m;
+ m = nullptr;
+ }
+ return m;
+}
+
+// Test direct report of gyroscope at normal rate level through ashmem direct channel
+void SensorTest::testGyroscopeSharedMemoryDirectReport(JNIEnv* env) {
+ constexpr int type = ASENSOR_TYPE_GYROSCOPE;
+ constexpr size_t kEventSize = sizeof(ASensorEvent);
+ constexpr size_t kNEvent = 500;
+ constexpr size_t kMemSize = kEventSize * kNEvent;
+
+ TestSensor sensor = mManager->getDefaultSensor(type);
+
+ if (sensor.getHighestDirectReportRateLevel() == ASENSOR_DIRECT_RATE_STOP
+ || !sensor.isDirectChannelTypeSupported(ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY)) {
+ // does not declare support
+ return;
+ }
+
+ std::unique_ptr<TestSharedMemory>
+ mem(TestSharedMemory::create(ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, kMemSize));
+ ASSERT_NE(mem, nullptr);
+ ASSERT_NE(mem->getBuffer(), nullptr);
+ ASSERT_GT(mem->getSharedMemoryFd(), 0);
+
+ char* buffer = mem->getBuffer();
+ // fill memory with data
+ for (size_t i = 0; i < kMemSize; ++i) {
+ buffer[i] = '\xcc';
+ }
+
+ int32_t channel;
+ channel = mManager->createDirectChannel(*mem);
+ ASSERT_GT(channel, 0);
+
+ // check memory is zeroed
+ for (size_t i = 0; i < kMemSize; ++i) {
+ ASSERT_EQ(buffer[i], '\0');
+ }
+
+ int32_t eventToken;
+ eventToken = mManager->configureDirectReport(sensor, channel, ASENSOR_DIRECT_RATE_NORMAL);
+ usleep(1500000); // sleep 1 sec for data, plus 0.5 sec for initialization
+ auto events = mem->parseEvents();
+
+ // allowed to be between 55% and 220% of nominal freq (50Hz)
+ ASSERT_GT(events.size(), 50 / 2);
+ ASSERT_LT(events.size(), static_cast<size_t>(110*1.5));
+
+ int64_t lastTimestamp = 0;
+ for (auto &e : events) {
+ ASSERT_EQ(e.type, type);
+ ASSERT_EQ(e.sensor, eventToken);
+ ASSERT_GT(e.timestamp, lastTimestamp);
+
+ ASensorVector &gyro = e.vector;
+ double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z);
+ // assert not drifting
+ ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/sa
+
+ lastTimestamp = e.timestamp;
+ }
+
+ // stop sensor and unregister channel
+ mManager->configureDirectReport(sensor, channel, ASENSOR_DIRECT_RATE_STOP);
+ mManager->destroyDirectChannel(channel);
+}
+} // namespace SensorTest
+} // namespace android
diff --git a/tests/sensor/jni/SensorTest.h b/tests/sensor/jni/SensorTest.h
new file mode 100644
index 0000000..5f8d703
--- /dev/null
+++ b/tests/sensor/jni/SensorTest.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef SENSOR_TEST_H
+#define SENSOR_TEST_H
+
+#include "nativeTestHelper.h"
+#include <android/sensor.h>
+#include <android/hardware_buffer.h>
+#include <android/sharedmem.h>
+
+#include <unordered_set>
+#include <vector>
+#include <sys/mman.h>
+#include <unistd.h>
+
+namespace android {
+namespace SensorTest {
+
+class TestSensor;
+class TestSensorManager;
+class TestSharedMemory;
+
+class SensorTest {
+public:
+ virtual bool SetUp();
+ virtual void TearDown();
+ virtual ~SensorTest() = default;
+
+ // tests
+ void testInitialized(JNIEnv *env);
+ void testGyroscopeSharedMemoryDirectReport(JNIEnv *env);
+private:
+ std::unique_ptr<TestSensorManager> mManager;
+};
+
+// NDK ASensorManager wrapper
+class TestSensorManager {
+public:
+ static TestSensorManager * getInstanceForPackage(const char *package);
+ virtual ~TestSensorManager();
+
+ TestSensor getDefaultSensor(int type);
+ int createDirectChannel(const TestSharedMemory &mem);
+ void destroyDirectChannel(int channel);
+ int configureDirectReport(TestSensor sensor, int channel, int rateLevel);
+ bool isValid() const { return mManager != nullptr; }
+private:
+ TestSensorManager(const char *package);
+ int createSharedMemoryDirectChannel(int fd, size_t size);
+ int createHardwareBufferDirectChannel(AHardwareBuffer const *buffer, size_t size);
+
+ ASensorManager *mManager; // singleton, does not need delete
+
+ // book keeping
+ std::unordered_set<int> mSensorDirectChannel;
+};
+
+// NDK ASensor warpper
+class TestSensor {
+public:
+ TestSensor(ASensor const *s) : mSensor(s) { }
+
+ int getType() const {
+ if (!isValid()) {
+ return -1;
+ }
+ return ASensor_getType(mSensor);
+ }
+
+ bool isDirectChannelTypeSupported(int channelType) const {
+ if (!isValid()) {
+ return false;
+ }
+ return ASensor_isDirectChannelTypeSupported(mSensor, channelType);
+ }
+
+ int getHighestDirectReportRateLevel() const {
+ if (!isValid()) {
+ return ASENSOR_DIRECT_RATE_STOP;
+ }
+ return ASensor_getHighestDirectReportRateLevel(mSensor);
+ }
+
+ operator ASensor const * () { return mSensor; }
+
+ bool isValid() const { return mSensor != nullptr; }
+private:
+ ASensor const * mSensor;
+};
+
+// Shared memory wrapper class
+class TestSharedMemory {
+public:
+ static TestSharedMemory* create(int type, size_t size);
+ char * getBuffer() const;
+ std::vector<ASensorEvent> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
+ virtual ~TestSharedMemory();
+
+ int getSharedMemoryFd() const {
+ return mSharedMemoryFd;
+ }
+
+ AHardwareBuffer const * getHardwareBuffer() const {
+ return mHardwareBuffer;
+ }
+
+ int getType() const {
+ return mType;
+ }
+
+ size_t getSize() const {
+ return mSize;
+ }
+private:
+ TestSharedMemory(int type, size_t size);
+ void release();
+
+ const int mType;
+ size_t mSize;
+ char* mBuffer;
+ int mSharedMemoryFd;
+ AHardwareBuffer *mHardwareBuffer;
+};
+} // namespace SensorTest
+} // namespace android
+
+#endif // SENSOR_TEST_H
diff --git a/tests/sensor/jni/android_view_cts_SensorNativeTest.cpp b/tests/sensor/jni/android_view_cts_SensorNativeTest.cpp
new file mode 100644
index 0000000..0c67928
--- /dev/null
+++ b/tests/sensor/jni/android_view_cts_SensorNativeTest.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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 "nativeTestHelper.h"
+#include "SensorTest.h"
+
+namespace {
+using android::SensorTest::SensorTest;
+
+jlong setUp(JNIEnv*, jclass) {
+ SensorTest *test = new SensorTest();
+ if (test != nullptr) {
+ test->SetUp();
+ }
+ return reinterpret_cast<jlong>(test);
+}
+
+void tearDown(JNIEnv*, jclass, jlong instance) {
+ delete reinterpret_cast<SensorTest *>(instance);
+}
+
+void test(JNIEnv* env, jclass, jlong instance) {
+ SensorTest *test = reinterpret_cast<SensorTest *>(instance);
+ ASSERT_NE(test, nullptr);
+
+ // test if SensorTest is intialized
+ test->testInitialized(env);
+
+ // test gyro direct report using shared memory buffer
+ test->testGyroscopeSharedMemoryDirectReport(env);
+}
+
+JNINativeMethod gMethods[] = {
+ { "nativeSetUp", "()J",
+ (void *) setUp},
+ { "nativeTearDown", "(J)V",
+ (void *) tearDown},
+ { "nativeTest", "(J)V",
+ (void *) test},
+};
+} // unamed namespace
+
+int register_android_view_cts_SensorNativeTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/hardware/cts/SensorNativeTest");
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/sensor/jni/nativeTestHelper.cpp b/tests/sensor/jni/nativeTestHelper.cpp
new file mode 100644
index 0000000..7c1b378
--- /dev/null
+++ b/tests/sensor/jni/nativeTestHelper.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 "nativeTestHelper.h"
+#include <cstdlib>
+#include <cstring>
+
+extern int register_android_view_cts_SensorNativeTest(JNIEnv* env);
+
+void fail(JNIEnv* env, const char* format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ char *msg;
+ vasprintf(&msg, format, args);
+ va_end(args);
+
+ jclass exClass;
+ const char *className = "java/lang/AssertionError";
+ exClass = env->FindClass(className);
+ env->ThrowNew(exClass, msg);
+ free(msg);
+}
+
+jint JNI_OnLoad(JavaVM *vm, void *) {
+ JNIEnv *env = NULL;
+ if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
+ return JNI_ERR;
+ }
+ if (register_android_view_cts_SensorNativeTest(env)) {
+ return JNI_ERR;
+ }
+ return JNI_VERSION_1_4;
+}
diff --git a/tests/sensor/jni/nativeTestHelper.h b/tests/sensor/jni/nativeTestHelper.h
new file mode 100644
index 0000000..cf7f1bd
--- /dev/null
+++ b/tests/sensor/jni/nativeTestHelper.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 <jni.h>
+
+#include <android/log.h>
+#define TAG "SensorNativeTest"
+#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
+
+#define ASSERT(condition, format, args...) \
+ if (!(condition)) { \
+ fail(env, format, ## args); \
+ return; \
+ }
+
+// gtest style assert
+#define ASSERT_TRUE(a) ASSERT((a), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_FALSE(a) ASSERT(!(a), "assert failed on (!" #a ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_EQ(a, b) \
+ ASSERT((a) == (b), "assert failed on (" #a " == " #b ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_NE(a, b) \
+ ASSERT((a) != (b), "assert failed on (" #a " != " #b ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_GT(a, b) \
+ ASSERT((a) > (b), "assert failed on (" #a " > " #b ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_GE(a, b) \
+ ASSERT((a) >= (b), "assert failed on (" #a " >= " #b ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_LT(a, b) \
+ ASSERT((a) < (b), "assert failed on (" #a " < " #b ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_LE(a, b) \
+ ASSERT((a) <= (b), "assert failed on (" #a " <= " #b ") at " __FILE__ ":%d", __LINE__)
+
+void fail(JNIEnv* env, const char* format, ...);
diff --git a/tests/sensor/src/android/hardware/cts/SensorNativeTest.java b/tests/sensor/src/android/hardware/cts/SensorNativeTest.java
new file mode 100644
index 0000000..7a05bf5
--- /dev/null
+++ b/tests/sensor/src/android/hardware/cts/SensorNativeTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.hardware.cts;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+
+/**
+ * Check sensor native library funcationality.
+ *
+ * This is the place to implement sensor NDK CTS tests.
+ */
+public class SensorNativeTest extends SensorTestCase {
+ private SensorManager mSensorManager;
+ private boolean mAreHifiSensorsSupported;
+ private boolean mVrHighPerformanceModeSupported;
+
+ protected native long nativeSetUp();
+ protected native void nativeTearDown(long instance);
+ private native void nativeTest(long instance);
+ private long mNativeInstance;
+
+ static {
+ System.loadLibrary("cts-sensors-ndk-jni");
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mNativeInstance = nativeSetUp();
+ assertTrue("create native instance failed", mNativeInstance != 0);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ nativeTearDown(mNativeInstance);
+ }
+
+ public void testNative() throws AssertionError {
+ nativeTest(mNativeInstance);
+ }
+}
diff --git a/tests/sensor/src/android/hardware/cts/SensorSupportTest.java b/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
index 3d1bc09..09e4711 100644
--- a/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
@@ -20,7 +20,6 @@
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.test.AndroidTestCase;
/**
* Checks if Hifi sensors or VR High performance mode sensors
@@ -35,7 +34,7 @@
* -w android.hardware.cts/android.test.AndroidJUnitRunner
* </pre>
*/
-public class SensorSupportTest extends AndroidTestCase {
+public class SensorSupportTest extends SensorTestCase {
private SensorManager mSensorManager;
private boolean mAreHifiSensorsSupported;
private boolean mVrHighPerformanceModeSupported;