blob: af8286008f4f91012e4a630f6dd38d887543c3d8 [file] [log] [blame] [edit]
/*
* 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 <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <linux/android/binder.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "../binder_module.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 | O_CLOEXEC);
ASSERT_GE(m_binderFd, 0);
m_buffer = mmap(nullptr, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0);
ASSERT_NE(m_buffer, (void *)nullptr);
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 = (uintptr_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:
/* The ioctl must either return 0, or if it doesn't errno should be accepted_errno */
void binderTestIoctlSuccessOrError(int cmd, void *arg, int accepted_errno) {
int ret;
ret = ioctl(m_binderFd, cmd, arg);
if (ret != 0) {
EXPECT_EQ(errno, accepted_errno);
}
}
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 = (uintptr_t)br;
bwr.read_size = sizeof(br);
binderTestIoctlErr1(BINDER_WRITE_READ, &bwr, EAGAIN);
EXPECT_EQ(0u, 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, OpenNoMmap) {
int binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC);
ASSERT_GE(binderFd, 0);
close(binderFd);
}
TEST_F(BinderDriverInterfaceTest, WriteReadNull) {
binderTestIoctlErr1(BINDER_WRITE_READ, nullptr, EFAULT);
}
TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNull) {
binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, nullptr, EFAULT, EINVAL);
}
TEST_F(BinderDriverInterfaceTest, SetMaxThreadsNull) {
binderTestIoctlErr2(BINDER_SET_MAX_THREADS, nullptr, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
}
TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNull) {
binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, nullptr, EFAULT, EINVAL);
}
TEST_F(BinderDriverInterfaceTest, VersionNull) {
binderTestIoctlErr2(BINDER_VERSION, nullptr, 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 = (uintptr_t)bc;
bwr.write_size = sizeof(bc);
binderTestIoctl(BINDER_WRITE_READ, &bwr);
EXPECT_EQ(sizeof(bc), bwr.write_consumed);
binderTestReadEmpty();
}
TEST_F(BinderDriverInterfaceTest, Transaction) {
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 = {
.ptr = {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 = (uintptr_t)&bc1;
bwr.write_size = sizeof(bc1);
bwr.read_buffer = (uintptr_t)&br;
bwr.read_size = sizeof(br);
{
SCOPED_TRACE("1st WriteRead");
binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr, EAGAIN);
}
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(0u, br.arg2.target.ptr);
EXPECT_EQ(0u, br.arg2.cookie);
EXPECT_EQ(0u, br.arg2.code);
EXPECT_EQ(0u, br.arg2.flags);
EXPECT_EQ(0u, br.arg2.data_size);
EXPECT_EQ(0u, 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 = (uintptr_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 = (uintptr_t)&bc;
bwr.write_size = sizeof(bc);
bwr.read_buffer = (uintptr_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();
}
TEST_F(BinderDriverInterfaceTest, RequestFrozenNotification) {
if (!android::ProcessState::isDriverFeatureEnabled(
android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
return;
}
binder_uintptr_t cookie = 1234;
struct {
uint32_t cmd0;
uint32_t arg0;
uint32_t cmd1;
struct binder_handle_cookie arg1;
} __attribute__((packed)) bc1 = {
.cmd0 = BC_INCREFS,
.arg0 = 0,
.cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
.arg1 =
{
.handle = 0,
.cookie = cookie,
},
};
struct {
uint32_t cmd0;
// Expecting a BR_FROZEN_BINDER since BC_REQUEST_FREEZE_NOTIFICATION
// above should lead to an immediate notification of the current state.
uint32_t cmd1;
struct binder_frozen_state_info arg1;
uint32_t pad[16];
} __attribute__((packed)) br1;
struct {
uint32_t cmd2;
binder_uintptr_t arg2;
uint32_t cmd3;
struct binder_handle_cookie arg3;
uint32_t cmd4;
uint32_t arg4;
} __attribute__((packed)) bc2 = {
// Tell kernel that userspace has done handling BR_FROZEN_BINDER.
.cmd2 = BC_FREEZE_NOTIFICATION_DONE,
.arg2 = cookie,
.cmd3 = BC_CLEAR_FREEZE_NOTIFICATION,
.arg3 =
{
.handle = 0,
.cookie = cookie,
},
.cmd4 = BC_DECREFS,
.arg4 = 0,
};
struct {
uint32_t cmd2;
uint32_t cmd3;
binder_uintptr_t arg3;
uint32_t pad[16];
} __attribute__((packed)) br2;
struct binder_write_read bwr1 = binder_write_read();
bwr1.write_buffer = (uintptr_t)&bc1;
bwr1.write_size = sizeof(bc1);
bwr1.read_buffer = (uintptr_t)&br1;
bwr1.read_size = sizeof(br1);
binderTestIoctl(BINDER_WRITE_READ, &bwr1);
EXPECT_EQ(sizeof(bc1), bwr1.write_consumed);
EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed);
EXPECT_EQ(BR_NOOP, br1.cmd0);
ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1);
EXPECT_FALSE(br1.arg1.is_frozen);
struct binder_write_read bwr2 = binder_write_read();
bwr2.write_buffer = (uintptr_t)&bc2;
bwr2.write_size = sizeof(bc2);
bwr2.read_buffer = (uintptr_t)&br2;
bwr2.read_size = sizeof(br2);
binderTestIoctl(BINDER_WRITE_READ, &bwr2);
EXPECT_EQ(sizeof(bc2), bwr2.write_consumed);
EXPECT_EQ(sizeof(br2) - sizeof(br2.pad), bwr2.read_consumed);
EXPECT_EQ(BR_NOOP, br2.cmd2);
EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br2.cmd3);
EXPECT_EQ(cookie, br2.arg3);
binderTestReadEmpty();
}
TEST_F(BinderDriverInterfaceTest, OverwritePendingFrozenNotification) {
if (!android::ProcessState::isDriverFeatureEnabled(
android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
return;
}
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_FREEZE_NOTIFICATION,
// This BC_REQUEST_FREEZE_NOTIFICATION should lead to a pending
// frozen notification inserted into the queue.
.arg1 =
{
.handle = 0,
.cookie = cookie,
},
// Send BC_CLEAR_FREEZE_NOTIFICATION before the above frozen
// notification has a chance of being sent. The notification should
// be overwritten. Userspace is expected to only receive
// BR_CLEAR_FREEZE_NOTIFICATION_DONE.
.cmd2 = BC_CLEAR_FREEZE_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 = (uintptr_t)&bc;
bwr.write_size = sizeof(bc);
bwr.read_buffer = (uintptr_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_FREEZE_NOTIFICATION_DONE, br.cmd1);
EXPECT_EQ(cookie, br.arg1);
binderTestReadEmpty();
}
TEST_F(BinderDriverInterfaceTest, ResendFrozenNotification) {
if (!android::ProcessState::isDriverFeatureEnabled(
android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
return;
}
binder_uintptr_t cookie = 1234;
struct {
uint32_t cmd0;
uint32_t arg0;
uint32_t cmd1;
struct binder_handle_cookie arg1;
} __attribute__((packed)) bc1 = {
.cmd0 = BC_INCREFS,
.arg0 = 0,
.cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
.arg1 =
{
.handle = 0,
.cookie = cookie,
},
};
struct {
uint32_t cmd0;
uint32_t cmd1;
struct binder_frozen_state_info arg1;
uint32_t pad[16];
} __attribute__((packed)) br1;
struct {
uint32_t cmd2;
struct binder_handle_cookie arg2;
} __attribute__((packed)) bc2 = {
// Clear the notification before acknowledging the in-flight
// BR_FROZEN_BINDER. Kernel should hold off sending
// BR_CLEAR_FREEZE_NOTIFICATION_DONE until the acknowledgement
// reaches kernel.
.cmd2 = BC_CLEAR_FREEZE_NOTIFICATION,
.arg2 =
{
.handle = 0,
.cookie = cookie,
},
};
struct {
uint32_t pad[16];
} __attribute__((packed)) br2;
struct {
uint32_t cmd3;
binder_uintptr_t arg3;
uint32_t cmd4;
uint32_t arg4;
} __attribute__((packed)) bc3 = {
// Send the acknowledgement. Now the kernel should send out
// BR_CLEAR_FREEZE_NOTIFICATION_DONE.
.cmd3 = BC_FREEZE_NOTIFICATION_DONE,
.arg3 = cookie,
.cmd4 = BC_DECREFS,
.arg4 = 0,
};
struct {
uint32_t cmd2;
uint32_t cmd3;
binder_uintptr_t arg3;
uint32_t pad[16];
} __attribute__((packed)) br3;
struct binder_write_read bwr1 = binder_write_read();
bwr1.write_buffer = (uintptr_t)&bc1;
bwr1.write_size = sizeof(bc1);
bwr1.read_buffer = (uintptr_t)&br1;
bwr1.read_size = sizeof(br1);
binderTestIoctl(BINDER_WRITE_READ, &bwr1);
EXPECT_EQ(sizeof(bc1), bwr1.write_consumed);
EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed);
EXPECT_EQ(BR_NOOP, br1.cmd0);
ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1);
EXPECT_FALSE(br1.arg1.is_frozen);
struct binder_write_read bwr2 = binder_write_read();
bwr2.write_buffer = (uintptr_t)&bc2;
bwr2.write_size = sizeof(bc2);
bwr2.read_buffer = (uintptr_t)&br2;
bwr2.read_size = sizeof(br2);
binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr2, EAGAIN);
binderTestReadEmpty();
struct binder_write_read bwr3 = binder_write_read();
bwr3.write_buffer = (uintptr_t)&bc3;
bwr3.write_size = sizeof(bc3);
bwr3.read_buffer = (uintptr_t)&br3;
bwr3.read_size = sizeof(br3);
binderTestIoctl(BINDER_WRITE_READ, &bwr3);
EXPECT_EQ(sizeof(bc3), bwr3.write_consumed);
EXPECT_EQ(sizeof(br3) - sizeof(br3.pad), bwr3.read_consumed);
EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br3.cmd3);
EXPECT_EQ(cookie, br3.arg3);
binderTestReadEmpty();
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv());
return RUN_ALL_TESTS();
}