summaryrefslogtreecommitdiffstats
path: root/libion
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2013-11-07 23:06:58 -0800
committerColin Cross <ccross@android.com>2013-12-19 19:31:46 -0800
commit363441b120aa7ff4ec7c639bac099e775c2ace69 (patch)
tree4aef851bb4d982f88748694f9e67baf6e480ed84 /libion
parentb04f75ab129e471eb0b45571f0c319c516de0c02 (diff)
downloadsystem_core-363441b120aa7ff4ec7c639bac099e775c2ace69.zip
system_core-363441b120aa7ff4ec7c639bac099e775c2ace69.tar.gz
system_core-363441b120aa7ff4ec7c639bac099e775c2ace69.tar.bz2
libion: initial unit tests
Change-Id: I5502b71d0c7c24d7fd59e4880033657f840b341a
Diffstat (limited to 'libion')
-rw-r--r--libion/Android.mk2
-rw-r--r--libion/tests/Android.mk34
-rw-r--r--libion/tests/allocate_test.cpp145
-rw-r--r--libion/tests/device_test.cpp568
-rw-r--r--libion/tests/exit_test.cpp227
-rw-r--r--libion/tests/formerly_valid_handle_test.cpp63
-rw-r--r--libion/tests/invalid_values_test.cpp186
-rw-r--r--libion/tests/ion_test_fixture.cpp73
-rw-r--r--libion/tests/ion_test_fixture.h46
-rw-r--r--libion/tests/map_test.cpp162
10 files changed, 1506 insertions, 0 deletions
diff --git a/libion/Android.mk b/libion/Android.mk
index 42e6f07..e5d495b 100644
--- a/libion/Android.mk
+++ b/libion/Android.mk
@@ -16,3 +16,5 @@ LOCAL_MODULE_TAGS := optional tests
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
LOCAL_SHARED_LIBRARIES := liblog
include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk
new file mode 100644
index 0000000..8dc7f9d
--- /dev/null
+++ b/libion/tests/Android.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2013 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)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ion-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_SHARED_LIBRARIES += libion
+LOCAL_STATIC_LIBRARIES += libgtest_main
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
+LOCAL_SRC_FILES := \
+ ion_test_fixture.cpp \
+ allocate_test.cpp \
+ formerly_valid_handle_test.cpp \
+ invalid_values_test.cpp \
+ map_test.cpp \
+ device_test.cpp \
+ exit_test.cpp
+include $(BUILD_NATIVE_TEST)
diff --git a/libion/tests/allocate_test.cpp b/libion/tests/allocate_test.cpp
new file mode 100644
index 0000000..e26b302
--- /dev/null
+++ b/libion/tests/allocate_test.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+#include "ion_test_fixture.h"
+
+class Allocate : public IonAllHeapsTest {
+};
+
+TEST_F(Allocate, Allocate)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ ion_user_handle_t handle = 0;
+ ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+ ASSERT_TRUE(handle != 0);
+ ASSERT_EQ(0, ion_free(m_ionFd, handle));
+ }
+ }
+}
+
+TEST_F(Allocate, AllocateCached)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ ion_user_handle_t handle = 0;
+ ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &handle));
+ ASSERT_TRUE(handle != 0);
+ ASSERT_EQ(0, ion_free(m_ionFd, handle));
+ }
+ }
+}
+
+TEST_F(Allocate, AllocateCachedNeedsSync)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ ion_user_handle_t handle = 0;
+ ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED_NEEDS_SYNC, &handle));
+ ASSERT_TRUE(handle != 0);
+ ASSERT_EQ(0, ion_free(m_ionFd, handle));
+ }
+ }
+}
+
+TEST_F(Allocate, RepeatedAllocate)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ ion_user_handle_t handle = 0;
+
+ for (unsigned int i = 0; i < 1024; i++) {
+ SCOPED_TRACE(::testing::Message() << "iteration " << i);
+ ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+ ASSERT_TRUE(handle != 0);
+ ASSERT_EQ(0, ion_free(m_ionFd, handle));
+ }
+ }
+ }
+}
+
+TEST_F(Allocate, Zeroed)
+{
+ void *zeroes = calloc(4096, 1);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int fds[16];
+ for (unsigned int i = 0; i < 16; i++) {
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, 0, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr = NULL;
+ ptr = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ memset(ptr, 0xaa, 4096);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ fds[i] = map_fd;
+ }
+
+ for (unsigned int i = 0; i < 16; i++) {
+ ASSERT_EQ(0, close(fds[i]));
+ }
+
+ int newIonFd = ion_open();
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(newIonFd, 4096, 0, heapMask, 0, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr = NULL;
+ ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, memcmp(ptr, zeroes, 4096));
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(zeroes);
+
+}
+
+TEST_F(Allocate, Large)
+{
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ ion_user_handle_t handle = 0;
+ ASSERT_EQ(-ENOMEM, ion_alloc(m_ionFd, 3UL*1024*1024*1024, 0, heapMask, 0, &handle));
+ }
+}
diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp
new file mode 100644
index 0000000..6f6e1bd
--- /dev/null
+++ b/libion/tests/device_test.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2013 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 <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/ion_test.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+#define ALIGN(x,y) (((x) + ((y) - 1)) & ~((y) - 1))
+
+class Device : public IonAllHeapsTest {
+ public:
+ virtual void SetUp();
+ virtual void TearDown();
+ int m_deviceFd;
+ void readDMA(int fd, void *buf, size_t size);
+ void writeDMA(int fd, void *buf, size_t size);
+ void readKernel(int fd, void *buf, size_t size);
+ void writeKernel(int fd, void *buf, size_t size);
+ void blowCache();
+ void dirtyCache(void *ptr, size_t size);
+};
+
+void Device::SetUp()
+{
+ IonAllHeapsTest::SetUp();
+ m_deviceFd = open("/dev/ion-test", O_RDWR);
+ ASSERT_GE(m_deviceFd, 0);
+}
+
+void Device::TearDown()
+{
+ ASSERT_EQ(0, close(m_deviceFd));
+ IonAllHeapsTest::TearDown();
+}
+
+void Device::readDMA(int fd, void *buf, size_t size)
+{
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+ struct ion_test_rw_data ion_test_rw_data = {
+ .ptr = (uint64_t)buf,
+ .offset = 0,
+ .size = size,
+ .write = 0,
+ };
+
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_DMA_MAPPING, &ion_test_rw_data));
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::writeDMA(int fd, void *buf, size_t size)
+{
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+ struct ion_test_rw_data ion_test_rw_data = {
+ .ptr = (uint64_t)buf,
+ .offset = 0,
+ .size = size,
+ .write = 1,
+ };
+
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_DMA_MAPPING, &ion_test_rw_data));
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::readKernel(int fd, void *buf, size_t size)
+{
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+ struct ion_test_rw_data ion_test_rw_data = {
+ .ptr = (uint64_t)buf,
+ .offset = 0,
+ .size = size,
+ .write = 0,
+ };
+
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_KERNEL_MAPPING, &ion_test_rw_data));
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::writeKernel(int fd, void *buf, size_t size)
+{
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+ struct ion_test_rw_data ion_test_rw_data = {
+ .ptr = (uint64_t)buf,
+ .offset = 0,
+ .size = size,
+ .write = 1,
+ };
+
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_KERNEL_MAPPING, &ion_test_rw_data));
+ ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::blowCache()
+{
+ const size_t bigger_than_cache = 8*1024*1024;
+ void *buf1 = malloc(bigger_than_cache);
+ void *buf2 = malloc(bigger_than_cache);
+ memset(buf1, 0xaa, bigger_than_cache);
+ memcpy(buf2, buf1, bigger_than_cache);
+ free(buf1);
+ free(buf2);
+}
+
+void Device::dirtyCache(void *ptr, size_t size)
+{
+ /* try to dirty cache lines */
+ for (size_t i = size-1; i > 0; i--) {
+ ((volatile char *)ptr)[i];
+ ((char *)ptr)[i] = i;
+ }
+}
+
+TEST_F(Device, KernelReadCached)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)ptr)[i] = i;
+
+ ((char*)buf)[4096] = 0x12;
+ readKernel(map_fd, buf, 4096);
+ ASSERT_EQ(((char*)buf)[4096], 0x12);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, KernelWriteCached)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)buf)[i] = i;
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ writeKernel(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, DMAReadCached)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)ptr)[i] = i;
+
+ readDMA(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, DMAWriteCached)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)buf)[i] = i;
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ writeDMA(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, KernelReadCachedNeedsSync)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)ptr)[i] = i;
+
+ ((char*)buf)[4096] = 0x12;
+ readKernel(map_fd, buf, 4096);
+ ASSERT_EQ(((char*)buf)[4096], 0x12);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, KernelWriteCachedNeedsSync)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)buf)[i] = i;
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ writeKernel(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, DMAReadCachedNeedsSync)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)ptr)[i] = i;
+
+ ion_sync_fd(m_ionFd, map_fd);
+
+ readDMA(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, DMAWriteCachedNeedsSync)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)buf)[i] = i;
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ writeDMA(map_fd, buf, 4096);
+
+ ion_sync_fd(m_ionFd, map_fd);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+TEST_F(Device, KernelRead)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = 0;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)ptr)[i] = i;
+
+ ((char*)buf)[4096] = 0x12;
+ readKernel(map_fd, buf, 4096);
+ ASSERT_EQ(((char*)buf)[4096], 0x12);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, KernelWrite)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)buf)[i] = i;
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = 0;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ writeKernel(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, DMARead)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = 0;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)ptr)[i] = i;
+
+ readDMA(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, DMAWrite)
+{
+ void *alloc = malloc(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+ for (int i = 0; i < 4096; i++)
+ ((char *)buf)[i] = i;
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = 0;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ writeDMA(map_fd, buf, 4096);
+
+ for (int i = 0; i < 4096; i++)
+ ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+
+ free(alloc);
+}
+
+TEST_F(Device, IsCached)
+{
+ void *buf = malloc(4096);
+
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ dirtyCache(ptr, 4096);
+
+ readDMA(map_fd, buf, 4096);
+
+ bool same = true;
+ for (int i = 4096-16; i >= 0; i -= 16)
+ if (((char *)buf)[i] != i)
+ same = false;
+ ASSERT_FALSE(same);
+
+ ASSERT_EQ(0, munmap(ptr, 4096));
+ ASSERT_EQ(0, close(map_fd));
+ }
+}
diff --git a/libion/tests/exit_test.cpp b/libion/tests/exit_test.cpp
new file mode 100644
index 0000000..cdd3e27
--- /dev/null
+++ b/libion/tests/exit_test.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2013 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class Exit : public IonAllHeapsTest {
+};
+
+TEST_F(Exit, WithAlloc)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ ion_user_handle_t handle = 0;
+
+ ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+ ASSERT_TRUE(handle != 0);
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+}
+
+TEST_F(Exit, WithAllocFd)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int handle_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &handle_fd));
+ ASSERT_NE(-1, handle_fd);
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+}
+
+TEST_F(Exit, WithRepeatedAllocFd)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ for (unsigned int i = 0; i < 1024; i++) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ ASSERT_EXIT({
+ int handle_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &handle_fd));
+ ASSERT_NE(-1, handle_fd);
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "")
+ << "failed on heap " << heapMask
+ << " and size " << size
+ << " on iteration " << i;
+ }
+ }
+ }
+}
+
+
+TEST_F(Exit, WithMapping)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+
+}
+
+TEST_F(Exit, WithPartialMapping)
+{
+ static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, munmap(ptr, size / 2));
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+}
+
+TEST_F(Exit, WithMappingCached)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+
+}
+
+TEST_F(Exit, WithPartialMappingCached)
+{
+ static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, munmap(ptr, size / 2));
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+}
+
+TEST_F(Exit, WithMappingNeedsSync)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+
+}
+
+TEST_F(Exit, WithPartialMappingNeedsSync)
+{
+ static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ EXPECT_EXIT({
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, munmap(ptr, size / 2));
+ exit(0);
+ }, ::testing::ExitedWithCode(0), "");
+ }
+ }
+}
diff --git a/libion/tests/formerly_valid_handle_test.cpp b/libion/tests/formerly_valid_handle_test.cpp
new file mode 100644
index 0000000..01ab8f3
--- /dev/null
+++ b/libion/tests/formerly_valid_handle_test.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class FormerlyValidHandle : public IonTest {
+ public:
+ virtual void SetUp();
+ virtual void TearDown();
+ ion_user_handle_t m_handle;
+};
+
+void FormerlyValidHandle::SetUp()
+{
+ IonTest::SetUp();
+ ASSERT_EQ(0, ion_alloc(m_ionFd, 4096, 0, 1/* ion_env->m_firstHeap */, 0, &m_handle));
+ ASSERT_TRUE(m_handle != 0);
+ ASSERT_EQ(0, ion_free(m_ionFd, m_handle));
+}
+
+void FormerlyValidHandle::TearDown()
+{
+ m_handle = 0;
+}
+
+TEST_F(FormerlyValidHandle, free)
+{
+ ASSERT_EQ(-EINVAL, ion_free(m_ionFd, m_handle));
+}
+
+TEST_F(FormerlyValidHandle, map)
+{
+ int map_fd;
+ unsigned char *ptr;
+
+ ASSERT_EQ(-EINVAL, ion_map(m_ionFd, m_handle, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+}
+
+TEST_F(FormerlyValidHandle, share)
+{
+ int share_fd;
+
+ ASSERT_EQ(-EINVAL, ion_share(m_ionFd, m_handle, &share_fd));
+}
diff --git a/libion/tests/invalid_values_test.cpp b/libion/tests/invalid_values_test.cpp
new file mode 100644
index 0000000..77fea17
--- /dev/null
+++ b/libion/tests/invalid_values_test.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2013 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class InvalidValues : public IonAllHeapsTest {
+ public:
+ virtual void SetUp();
+ virtual void TearDown();
+ ion_user_handle_t m_validHandle;
+ int m_validShareFd;
+ ion_user_handle_t const m_badHandle = -1;
+};
+
+void InvalidValues::SetUp()
+{
+ IonAllHeapsTest::SetUp();
+ ASSERT_EQ(0, ion_alloc(m_ionFd, 4096, 0, m_firstHeap, 0, &m_validHandle))
+ << m_ionFd << " " << m_firstHeap;
+ ASSERT_TRUE(m_validHandle != 0);
+ ASSERT_EQ(0, ion_share(m_ionFd, m_validHandle, &m_validShareFd));
+}
+
+void InvalidValues::TearDown()
+{
+ ASSERT_EQ(0, ion_free(m_ionFd, m_validHandle));
+ ASSERT_EQ(0, close(m_validShareFd));
+ m_validHandle = 0;
+ IonAllHeapsTest::TearDown();
+}
+
+TEST_F(InvalidValues, ion_close)
+{
+ EXPECT_EQ(-EBADF, ion_close(-1));
+}
+
+TEST_F(InvalidValues, ion_alloc)
+{
+ ion_user_handle_t handle;
+ /* invalid ion_fd */
+ int ret = ion_alloc(0, 4096, 0, m_firstHeap, 0, &handle);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion_fd */
+ EXPECT_EQ(-EBADF, ion_alloc(-1, 4096, 0, m_firstHeap, 0, &handle));
+ /* no heaps */
+ EXPECT_EQ(-ENODEV, ion_alloc(m_ionFd, 4096, 0, 0, 0, &handle));
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ /* zero size */
+ EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 0, 0, heapMask, 0, &handle));
+ /* too large size */
+ EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, -1, 0, heapMask, 0, &handle));
+ /* bad alignment */
+ EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 4096, -1, heapMask, 0, &handle));
+ /* NULL handle */
+ EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 4096, 0, heapMask, 0, NULL));
+ }
+}
+
+TEST_F(InvalidValues, ion_alloc_fd)
+{
+ int fd;
+ /* invalid ion_fd */
+ int ret = ion_alloc_fd(0, 4096, 0, m_firstHeap, 0, &fd);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion_fd */
+ EXPECT_EQ(-EBADF, ion_alloc_fd(-1, 4096, 0, m_firstHeap, 0, &fd));
+ /* no heaps */
+ EXPECT_EQ(-ENODEV, ion_alloc_fd(m_ionFd, 4096, 0, 0, 0, &fd));
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ /* zero size */
+ EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 0, 0, heapMask, 0, &fd));
+ /* too large size */
+ EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, -1, 0, heapMask, 0, &fd));
+ /* bad alignment */
+ EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 4096, -1, heapMask, 0, &fd));
+ /* NULL handle */
+ EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, 0, NULL));
+ }
+}
+
+TEST_F(InvalidValues, ion_free)
+{
+ /* invalid ion fd */
+ int ret = ion_free(0, m_validHandle);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion fd */
+ EXPECT_EQ(-EBADF, ion_free(-1, m_validHandle));
+ /* zero handle */
+ EXPECT_EQ(-EINVAL, ion_free(m_ionFd, 0));
+ /* bad handle */
+ EXPECT_EQ(-EINVAL, ion_free(m_ionFd, m_badHandle));
+}
+
+TEST_F(InvalidValues, ion_map)
+{
+ int map_fd;
+ unsigned char *ptr;
+
+ /* invalid ion fd */
+ int ret = ion_map(0, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion fd */
+ EXPECT_EQ(-EBADF, ion_map(-1, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+ /* zero handle */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, 0, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+ /* bad handle */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_badHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+ /* zero length */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 0, PROT_READ, 0, 0, &ptr, &map_fd));
+ /* bad prot */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, -1, 0, 0, &ptr, &map_fd));
+ /* bad offset */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, -1, &ptr, &map_fd));
+ /* NULL ptr */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, 0, NULL, &map_fd));
+ /* NULL map_fd */
+ EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, NULL));
+}
+
+TEST_F(InvalidValues, ion_share)
+{
+ int share_fd;
+
+ /* invalid ion fd */
+ int ret = ion_share(0, m_validHandle, &share_fd);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion fd */
+ EXPECT_EQ(-EBADF, ion_share(-1, m_validHandle, &share_fd));
+ /* zero handle */
+ EXPECT_EQ(-EINVAL, ion_share(m_ionFd, 0, &share_fd));
+ /* bad handle */
+ EXPECT_EQ(-EINVAL, ion_share(m_ionFd, m_badHandle, &share_fd));
+ /* NULL share_fd */
+ EXPECT_EQ(-EINVAL, ion_share(m_ionFd, m_validHandle, NULL));
+}
+
+TEST_F(InvalidValues, ion_import)
+{
+ ion_user_handle_t handle;
+
+ /* invalid ion fd */
+ int ret = ion_import(0, m_validShareFd, &handle);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion fd */
+ EXPECT_EQ(-EBADF, ion_import(-1, m_validShareFd, &handle));
+ /* bad share_fd */
+ EXPECT_EQ(-EINVAL, ion_import(m_ionFd, 0, &handle));
+ /* invalid share_fd */
+ EXPECT_EQ(-EBADF, ion_import(m_ionFd, -1, &handle));
+ /* NULL handle */
+ EXPECT_EQ(-EINVAL, ion_import(m_ionFd, m_validShareFd, NULL));
+}
+
+TEST_F(InvalidValues, ion_sync_fd)
+{
+ /* invalid ion fd */
+ int ret = ion_sync_fd(0, m_validShareFd);
+ EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+ /* invalid ion fd */
+ EXPECT_EQ(-EBADF, ion_sync_fd(-1, m_validShareFd));
+ /* bad share_fd */
+ EXPECT_EQ(-EINVAL, ion_sync_fd(m_ionFd, 0));
+ /* invalid share_fd */
+ EXPECT_EQ(-EBADF, ion_sync_fd(m_ionFd, -1));
+}
diff --git a/libion/tests/ion_test_fixture.cpp b/libion/tests/ion_test_fixture.cpp
new file mode 100644
index 0000000..e20c730
--- /dev/null
+++ b/libion/tests/ion_test_fixture.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 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 <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+IonTest::IonTest() : m_ionFd(-1)
+{
+}
+
+void IonTest::SetUp() {
+ m_ionFd = ion_open();
+ ASSERT_GE(m_ionFd, 0);
+}
+
+void IonTest::TearDown() {
+ ion_close(m_ionFd);
+}
+
+IonAllHeapsTest::IonAllHeapsTest() :
+ m_firstHeap(0),
+ m_lastHeap(0),
+ m_allHeaps()
+{
+}
+
+void IonAllHeapsTest::SetUp() {
+ int fd = ion_open();
+ ASSERT_GE(fd, 0);
+
+ for (int i = 1; i != 0; i <<= 1) {
+ ion_user_handle_t handle = 0;
+ int ret;
+ ret = ion_alloc(fd, 4096, 0, i, 0, &handle);
+ if (ret == 0 && handle != 0) {
+ ion_free(fd, handle);
+ if (!m_firstHeap) {
+ m_firstHeap = i;
+ }
+ m_lastHeap = i;
+ m_allHeaps.push_back(i);
+ } else {
+ ASSERT_EQ(-ENODEV, ret);
+ }
+ }
+ ion_close(fd);
+
+ EXPECT_NE(0U, m_firstHeap);
+ EXPECT_NE(0U, m_lastHeap);
+
+ RecordProperty("Heaps", m_allHeaps.size());
+ IonTest::SetUp();
+}
+
+void IonAllHeapsTest::TearDown() {
+ IonTest::TearDown();
+}
diff --git a/libion/tests/ion_test_fixture.h b/libion/tests/ion_test_fixture.h
new file mode 100644
index 0000000..4098214
--- /dev/null
+++ b/libion/tests/ion_test_fixture.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 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 ION_TEST_FIXTURE_H_
+#define ION_TEST_FIXTURE_H_
+
+#include <gtest/gtest.h>
+
+using ::testing::Test;
+
+class IonTest : public virtual Test {
+ public:
+ IonTest();
+ virtual ~IonTest() {};
+ virtual void SetUp();
+ virtual void TearDown();
+ int m_ionFd;
+};
+
+class IonAllHeapsTest : public IonTest {
+ public:
+ IonAllHeapsTest();
+ virtual ~IonAllHeapsTest() {};
+ virtual void SetUp();
+ virtual void TearDown();
+
+ unsigned int m_firstHeap;
+ unsigned int m_lastHeap;
+
+ std::vector<unsigned int> m_allHeaps;
+};
+
+#endif /* ION_TEST_FIXTURE_H_ */
diff --git a/libion/tests/map_test.cpp b/libion/tests/map_test.cpp
new file mode 100644
index 0000000..c006dc8
--- /dev/null
+++ b/libion/tests/map_test.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2013 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class Map : public IonAllHeapsTest {
+};
+
+TEST_F(Map, MapHandle)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ ion_user_handle_t handle = 0;
+
+ ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+ ASSERT_TRUE(handle != 0);
+
+ int map_fd = -1;
+ unsigned char *ptr = NULL;
+ ASSERT_EQ(0, ion_map(m_ionFd, handle, size, PROT_READ | PROT_WRITE, MAP_SHARED, 0, &ptr, &map_fd));
+ ASSERT_TRUE(ptr != NULL);
+ ASSERT_GE(map_fd, 0);
+
+ ASSERT_EQ(0, close(map_fd));
+
+ ASSERT_EQ(0, ion_free(m_ionFd, handle));
+
+ memset(ptr, 0xaa, size);
+
+ ASSERT_EQ(0, munmap(ptr, size));
+ }
+ }
+}
+
+TEST_F(Map, MapFd)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, close(map_fd));
+
+ memset(ptr, 0xaa, size);
+
+ ASSERT_EQ(0, munmap(ptr, size));
+ }
+ }
+}
+
+TEST_F(Map, MapOffset)
+{
+ for (unsigned int heapMask : m_allHeaps) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ int map_fd = -1;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, PAGE_SIZE * 2, 0, heapMask, 0, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ unsigned char *ptr;
+ ptr = (unsigned char *)mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ memset(ptr, 0, PAGE_SIZE);
+ memset(ptr + PAGE_SIZE, 0xaa, PAGE_SIZE);
+
+ ASSERT_EQ(0, munmap(ptr, PAGE_SIZE * 2));
+
+ ptr = (unsigned char *)mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, PAGE_SIZE);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(ptr[0], 0xaa);
+ ASSERT_EQ(ptr[PAGE_SIZE - 1], 0xaa);
+
+ ASSERT_EQ(0, munmap(ptr, PAGE_SIZE));
+
+ ASSERT_EQ(0, close(map_fd));
+ }
+}
+
+TEST_F(Map, MapCached)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, close(map_fd));
+
+ memset(ptr, 0xaa, size);
+
+ ASSERT_EQ(0, munmap(ptr, size));
+ }
+ }
+}
+
+TEST_F(Map, MapCachedNeedsSync)
+{
+ static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+ for (unsigned int heapMask : m_allHeaps) {
+ for (size_t size : allocationSizes) {
+ SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+ SCOPED_TRACE(::testing::Message() << "size " << size);
+ int map_fd = -1;
+ unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, flags, &map_fd));
+ ASSERT_GE(map_fd, 0);
+
+ void *ptr;
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+ ASSERT_TRUE(ptr != NULL);
+
+ ASSERT_EQ(0, close(map_fd));
+
+ memset(ptr, 0xaa, size);
+
+ ASSERT_EQ(0, munmap(ptr, size));
+ }
+ }
+}