OSDN Git Service

Add binder driver interface test
authorRiley Andrews <riandrews@google.com>
Thu, 18 Dec 2014 19:54:32 +0000 (11:54 -0800)
committerRiley Andrews <riandrews@google.com>
Fri, 19 Dec 2014 00:38:27 +0000 (00:38 +0000)
Test ioctls and some binder commands without using libbinder.

Change-Id: I86dde56ff1380bca17d086021ac5324dc5210354

libs/binder/tests/Android.mk [new file with mode: 0644]
libs/binder/tests/binderDriverInterfaceTest.cpp [new file with mode: 0644]

diff --git a/libs/binder/tests/Android.mk b/libs/binder/tests/Android.mk
new file mode 100644 (file)
index 0000000..20c0af8
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2014 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)
+
+ifneq ($(TARGET_USES_64_BIT_BINDER),true)
+ifneq ($(TARGET_IS_64_BIT),true)
+LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
+endif
+endif
+
+LOCAL_MODULE := binderDriverInterfaceTest
+LOCAL_SRC_FILES := binderDriverInterfaceTest.cpp
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
new file mode 100644 (file)
index 0000000..acb7d49
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2014 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gtest/gtest.h>
+#include <linux/binder.h>
+#include <binder/IBinder.h>
+#include <sys/mman.h>
+#include <poll.h>
+
+#define BINDER_DEV_NAME "/dev/binder"
+
+testing::Environment* binder_env;
+
+class BinderDriverInterfaceTestEnv : public ::testing::Environment {
+        virtual void SetUp() {
+            int ret;
+            uint32_t max_threads = 0;
+
+            m_binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK);
+            ASSERT_GE(m_binderFd, 0);
+            m_buffer = mmap(NULL, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0);
+            ASSERT_NE(m_buffer, (void *)NULL);
+            ret = ioctl(m_binderFd, BINDER_SET_MAX_THREADS, &max_threads);
+            EXPECT_EQ(0, ret);
+            EnterLooper();
+        }
+        virtual void TearDown() {
+            close(m_binderFd);
+        }
+    private:
+        int m_binderFd;
+        void *m_buffer;
+    public:
+        int getBinderFd(void) {
+            return m_binderFd;
+        }
+        void EnterLooper(void) {
+            int ret;
+            const uint32_t bc[] = {
+                BC_ENTER_LOOPER,
+            };
+            struct binder_write_read bwr = binder_write_read();
+            bwr.write_buffer = (intptr_t)bc;
+            bwr.write_size = sizeof(bc);
+            ret = ioctl(m_binderFd, BINDER_WRITE_READ, &bwr);
+            EXPECT_EQ(0, ret);
+            if (ret < 0) {
+                    EXPECT_EQ(0, errno);
+            }
+            EXPECT_EQ(sizeof(bc), bwr.write_consumed);
+        }
+};
+
+class BinderDriverInterfaceTest : public ::testing::Test {
+    public:
+        virtual void SetUp() {
+            m_binderFd = static_cast<BinderDriverInterfaceTestEnv *>(binder_env)->getBinderFd();
+        }
+        virtual void TearDown() {
+        }
+    protected:
+        void binderTestIoctlRetErr2(int cmd, void *arg, int expect_ret, int expect_errno, int accept_errno) {
+            int ret;
+
+            ret = ioctl(m_binderFd, cmd, arg);
+            EXPECT_EQ(expect_ret, ret);
+            if (ret < 0) {
+                if (errno != accept_errno)
+                    EXPECT_EQ(expect_errno, errno);
+            }
+        }
+        void binderTestIoctlErr2(int cmd, void *arg, int expect_errno, int accept_errno) {
+            binderTestIoctlRetErr2(cmd, arg, -1, expect_errno, accept_errno);
+        }
+        void binderTestIoctlErr1(int cmd, void *arg, int expect_errno) {
+            binderTestIoctlErr2(cmd, arg, expect_errno, expect_errno);
+        }
+        void binderTestIoctl(int cmd, void *arg) {
+            binderTestIoctlRetErr2(cmd, arg, 0, 0, 0);
+        }
+        void binderTestIoctlUnimplemented(int cmd, void *arg) {
+            int ret;
+
+            ret = ioctl(m_binderFd, cmd, arg);
+            if (ret < 0) {
+                /* Not currently implmented. Allow ret == -1, errno == EINVAL */
+                EXPECT_EQ(-1, ret);
+                EXPECT_EQ(EINVAL, errno);
+            }
+        }
+        void binderTestReadEmpty(void) {
+            size_t i;
+            uint32_t br[32];
+            struct binder_write_read bwr = binder_write_read();
+            SCOPED_TRACE("TestReadEmpty");
+            bwr.read_buffer = (intptr_t)br;
+            bwr.read_size = sizeof(br);
+            binderTestIoctlErr1(BINDER_WRITE_READ, &bwr, EAGAIN);
+            EXPECT_EQ(0, bwr.read_consumed);
+            for (i = 0; i * sizeof(uint32_t) < bwr.read_consumed; i++) {
+                SCOPED_TRACE(testing::Message() << "i = " << i);
+                EXPECT_EQ(BR_NOOP, br[i]);
+            }
+        }
+        void binderWaitForReadData(int timeout_ms) {
+            int ret;
+            pollfd pfd = pollfd();
+
+            pfd.fd = m_binderFd;
+            pfd.events = POLLIN;
+            ret = poll(&pfd, 1, timeout_ms);
+            EXPECT_EQ(1, ret);
+        }
+    private:
+        int m_binderFd;
+};
+
+TEST_F(BinderDriverInterfaceTest, Version) {
+    struct binder_version version;
+    binderTestIoctl(BINDER_VERSION, &version);
+    ASSERT_EQ(BINDER_CURRENT_PROTOCOL_VERSION, version.protocol_version);
+}
+
+TEST_F(BinderDriverInterfaceTest, WriteReadNull) {
+    binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT);
+}
+
+TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNull) {
+    binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, NULL, EFAULT, EINVAL);
+}
+
+TEST_F(BinderDriverInterfaceTest, SetMaxThreadsNull) {
+    binderTestIoctlErr2(BINDER_SET_MAX_THREADS, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
+}
+
+TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNull) {
+    binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, NULL, EFAULT, EINVAL);
+}
+
+TEST_F(BinderDriverInterfaceTest, VersionNull) {
+    binderTestIoctlErr2(BINDER_VERSION, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
+}
+
+TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNoTest) {
+    int64_t idle_timeout = 100000;
+    binderTestIoctlUnimplemented(BINDER_SET_IDLE_TIMEOUT, &idle_timeout);
+}
+
+TEST_F(BinderDriverInterfaceTest, SetMaxThreads) {
+    uint32_t max_threads = 0;
+    binderTestIoctl(BINDER_SET_MAX_THREADS, &max_threads);
+}
+
+TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNoTest) {
+    int idle_priority = 0;
+    binderTestIoctlUnimplemented(BINDER_SET_IDLE_PRIORITY, &idle_priority);
+}
+
+TEST_F(BinderDriverInterfaceTest, SetContextMgrBusy) {
+    int32_t dummy = 0;
+    binderTestIoctlErr1(BINDER_SET_CONTEXT_MGR, &dummy, EBUSY);
+}
+
+TEST_F(BinderDriverInterfaceTest, ThreadExit) {
+    int32_t dummy = 0;
+    binderTestIoctl(BINDER_THREAD_EXIT, &dummy);
+    static_cast<BinderDriverInterfaceTestEnv *>(binder_env)->EnterLooper();
+}
+
+TEST_F(BinderDriverInterfaceTest, WriteReadEmpty) {
+    struct binder_write_read bwr = binder_write_read();
+    binderTestIoctl(BINDER_WRITE_READ, &bwr);
+}
+
+TEST_F(BinderDriverInterfaceTest, Read) {
+    binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, IncRefsAcquireReleaseDecRefs) {
+    const uint32_t bc[] = {
+        BC_INCREFS,
+        0,
+        BC_ACQUIRE,
+        0,
+        BC_RELEASE,
+        0,
+        BC_DECREFS,
+        0,
+    };
+    struct binder_write_read bwr = binder_write_read();
+    bwr.write_buffer = (intptr_t)bc;
+    bwr.write_size = sizeof(bc);
+    binderTestIoctl(BINDER_WRITE_READ, &bwr);
+    EXPECT_EQ(sizeof(bc), bwr.write_consumed);
+    binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, Transaction) {
+    binder_uintptr_t cookie = 1234;
+    struct {
+        uint32_t cmd1;
+        struct binder_transaction_data arg1;
+    } __attribute__((packed)) bc1 = {
+        .cmd1 = BC_TRANSACTION,
+        .arg1 = {
+            .target = { 0 },
+            .cookie = 0,
+            .code = android::IBinder::PING_TRANSACTION,
+            .flags = 0,
+            .sender_pid = 0,
+            .sender_euid = 0,
+            .data_size = 0,
+            .offsets_size = 0,
+            .data = {0, 0},
+        },
+    };
+    struct {
+        uint32_t cmd0;
+        uint32_t cmd1;
+        uint32_t cmd2;
+        binder_transaction_data arg2;
+        uint32_t pad[16];
+    } __attribute__((packed)) br;
+    struct binder_write_read bwr = binder_write_read();
+
+    bwr.write_buffer = (intptr_t)&bc1;
+    bwr.write_size = sizeof(bc1);
+    bwr.read_buffer = (intptr_t)&br;
+    bwr.read_size = sizeof(br);
+
+    {
+        SCOPED_TRACE("1st WriteRead");
+        binderTestIoctl(BINDER_WRITE_READ, &bwr);
+    }
+    EXPECT_EQ(sizeof(bc1), bwr.write_consumed);
+    if (bwr.read_consumed < offsetof(typeof(br), pad)) {
+        SCOPED_TRACE("2nd WriteRead");
+        binderWaitForReadData(10000);
+        binderTestIoctl(BINDER_WRITE_READ, &bwr);
+    }
+    EXPECT_EQ(offsetof(typeof(br), pad), bwr.read_consumed);
+    if (bwr.read_consumed > offsetof(typeof(br), cmd0))
+        EXPECT_EQ(BR_NOOP, br.cmd0);
+    if (bwr.read_consumed > offsetof(typeof(br), cmd1))
+        EXPECT_EQ(BR_TRANSACTION_COMPLETE, br.cmd1);
+    if (bwr.read_consumed > offsetof(typeof(br), cmd2))
+        EXPECT_EQ(BR_REPLY, br.cmd2);
+    if (bwr.read_consumed >= offsetof(typeof(br), pad)) {
+        EXPECT_EQ(0, br.arg2.target.ptr);
+        EXPECT_EQ(0, br.arg2.cookie);
+        EXPECT_EQ(0, br.arg2.code);
+        EXPECT_EQ(0, br.arg2.flags);
+        EXPECT_EQ(0, br.arg2.data_size);
+        EXPECT_EQ(0, br.arg2.offsets_size);
+
+        SCOPED_TRACE("3rd WriteRead");
+
+        binderTestReadEmpty();
+
+        struct {
+            uint32_t cmd1;
+            binder_uintptr_t arg1;
+        } __attribute__((packed)) bc2 = {
+            .cmd1 = BC_FREE_BUFFER,
+            .arg1 = br.arg2.data.ptr.buffer,
+        };
+
+        bwr.write_buffer = (intptr_t)&bc2;
+        bwr.write_size = sizeof(bc2);
+        bwr.write_consumed = 0;
+        bwr.read_size = 0;
+
+        binderTestIoctl(BINDER_WRITE_READ, &bwr);
+        EXPECT_EQ(sizeof(bc2), bwr.write_consumed);
+    }
+    binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) {
+    binder_uintptr_t cookie = 1234;
+    struct {
+        uint32_t cmd0;
+        uint32_t arg0;
+        uint32_t cmd1;
+        struct binder_handle_cookie arg1;
+        uint32_t cmd2;
+        struct binder_handle_cookie arg2;
+        uint32_t cmd3;
+        uint32_t arg3;
+    } __attribute__((packed)) bc = {
+        .cmd0 = BC_INCREFS,
+        .arg0 = 0,
+        .cmd1 = BC_REQUEST_DEATH_NOTIFICATION,
+        .arg1 = {
+            .handle = 0,
+            .cookie = cookie,
+        },
+        .cmd2 = BC_CLEAR_DEATH_NOTIFICATION,
+        .arg2 = {
+            .handle = 0,
+            .cookie = cookie,
+        },
+        .cmd3 = BC_DECREFS,
+        .arg3 = 0,
+    };
+    struct {
+        uint32_t cmd0;
+        uint32_t cmd1;
+        binder_uintptr_t arg1;
+        uint32_t pad[16];
+    } __attribute__((packed)) br;
+    struct binder_write_read bwr = binder_write_read();
+
+    bwr.write_buffer = (intptr_t)&bc;
+    bwr.write_size = sizeof(bc);
+    bwr.read_buffer = (intptr_t)&br;
+    bwr.read_size = sizeof(br);
+
+    binderTestIoctl(BINDER_WRITE_READ, &bwr);
+    EXPECT_EQ(sizeof(bc), bwr.write_consumed);
+    EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed);
+    EXPECT_EQ(BR_NOOP, br.cmd0);
+    EXPECT_EQ(BR_CLEAR_DEATH_NOTIFICATION_DONE, br.cmd1);
+    EXPECT_EQ(cookie, br.arg1);
+    binderTestReadEmpty();
+}
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv());
+
+    return RUN_ALL_TESTS();
+}
+