blob: 773106ee914fbadc340a012742490790c65a064e [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libprotobinder/binder_manager.h"
#include <string.h>
#include <base/bind.h>
#include <base/macros.h>
#include <base/memory/scoped_ptr.h>
#include <base/memory/weak_ptr.h>
#include <gtest/gtest.h>
#include "libprotobinder/binder_driver_stub.h"
#include "libprotobinder/binder_host.h"
#include "libprotobinder/binder_proxy.h"
#include "libprotobinder/status.h"
namespace protobinder {
class BinderTest : public testing::Test {
public:
BinderTest()
: got_death_callback_(false),
got_transact_callback_(false),
weak_ptr_factory_(this) {
// Configure BinderManager to use the stub driver.
// BinderManager takes ownership of BinderDriverStub.
driver_ = new BinderDriverStub();
scoped_ptr<BinderManager> manager(
new BinderManager(std::unique_ptr<BinderDriverInterface>(driver_)));
BinderManagerInterface::SetForTesting(manager.Pass());
}
~BinderTest() override {
BinderManagerInterface::SetForTesting(scoped_ptr<BinderManagerInterface>());
}
void HandleBinderDeath() { got_death_callback_ = true; }
void HandleTransaction() { got_transact_callback_ = true; }
protected:
// Checks binder transaction data presented to the driver
// matches what is provided in a transaction.
void CheckTransaction(struct binder_transaction_data* data,
uint32_t handle,
uint32_t code,
bool one_way) {
ASSERT_NE(nullptr, data);
EXPECT_EQ(handle, data->target.handle);
EXPECT_EQ(code, data->code);
EXPECT_EQ(code, data->code);
unsigned int flags = TF_ACCEPT_FDS;
flags |= one_way ? TF_ONE_WAY : 0;
EXPECT_EQ(flags, data->flags);
}
BinderDriverStub* driver_; // Not owned.
bool got_death_callback_;
bool got_transact_callback_;
base::WeakPtrFactory<BinderTest> weak_ptr_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(BinderTest);
};
class HostTest : public BinderHost {
public:
explicit HostTest(const base::Closure& closure)
: transact_callback_(closure) {}
~HostTest() override {}
enum CommandCodes { GOOD_TRANSACTION = 1, BAD_TRANSACTION = 2 };
Status OnTransact(uint32_t code,
Parcel* data,
Parcel* reply,
bool one_way) override {
transact_callback_.Run();
switch (code) {
case GOOD_TRANSACTION: {
int val = -1;
EXPECT_TRUE(data->ReadInt32(&val));
EXPECT_EQ(0xDEAD, val);
reply->WriteInt32(0xC0DE);
return STATUS_OK();
}
case BAD_TRANSACTION: {
return STATUS_APP_ERROR(0xDEAD, "Oh No..");
}
default:
NOTREACHED();
}
// Should never get here.
return STATUS_OK();
}
private:
base::Closure transact_callback_;
DISALLOW_COPY_AND_ASSIGN(HostTest);
};
TEST_F(BinderTest, BasicTransaction) {
Parcel data;
uint32_t handle = 0x1111;
uint32_t code = 0x2222;
bool one_way = true;
Status status = BinderManagerInterface::Get()->Transact(handle, code, data,
nullptr, one_way);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
handle = 0x3333;
code = 0x4444;
status = BinderManagerInterface::Get()->Transact(handle, code, data, nullptr,
one_way);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
handle = 0x5555;
code = 0x6666;
status = BinderManagerInterface::Get()->Transact(handle, code, data, nullptr,
one_way);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
EXPECT_EQ(0, driver_->LastTransactionData()->data_size);
EXPECT_EQ(0, driver_->LastTransactionData()->offsets_size);
}
TEST_F(BinderTest, DeadEndpointTransaction) {
Parcel data;
uint32_t handle = BinderDriverStub::BAD_ENDPOINT;
uint32_t code = 0;
bool one_way = true;
Status status = BinderManagerInterface::Get()->Transact(handle, code, data,
nullptr, one_way);
EXPECT_FALSE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
}
TEST_F(BinderTest, OneWayDataTransaction) {
Parcel data;
uint32_t handle = 0x1111;
uint32_t code = 0x2222;
bool one_way = true;
data.WriteInt32(100);
data.WriteString("Yet Another IPC...");
Status status = BinderManagerInterface::Get()->Transact(handle, code, data,
nullptr, one_way);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
// Check the data sent to the driver is correct.
EXPECT_EQ(data.Len(), driver_->LastTransactionData()->data_size);
EXPECT_EQ(0, driver_->LastTransactionData()->offsets_size);
ASSERT_NE(0, driver_->LastTransactionData()->data.ptr.buffer);
EXPECT_EQ(0, memcmp(data.Data(),
reinterpret_cast<void*>(
driver_->LastTransactionData()->data.ptr.buffer),
data.Len()));
}
TEST_F(BinderTest, OneWayDataAndObjectsTransaction) {
Parcel data;
uint32_t handle = 0x1111;
uint32_t code = 0x2222;
bool one_way = true;
data.WriteInt32(100);
data.WriteString("Yet Another IPC...");
data.WriteFd(10);
data.WriteFd(20);
Status status = BinderManagerInterface::Get()->Transact(handle, code, data,
nullptr, one_way);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
// Check that the data and offset buffers sent to the driver are correct.
EXPECT_EQ(data.Len(), driver_->LastTransactionData()->data_size);
EXPECT_EQ(data.ObjectCount() * sizeof(binder_size_t),
driver_->LastTransactionData()->offsets_size);
ASSERT_NE(0, driver_->LastTransactionData()->data.ptr.buffer);
EXPECT_EQ(0, memcmp(data.Data(),
reinterpret_cast<void*>(
driver_->LastTransactionData()->data.ptr.buffer),
data.Len()));
ASSERT_NE(0, driver_->LastTransactionData()->data.ptr.offsets);
EXPECT_EQ(0, memcmp(data.ObjectData(),
reinterpret_cast<void*>(
driver_->LastTransactionData()->data.ptr.offsets),
data.ObjectCount() * sizeof(binder_size_t)));
}
TEST_F(BinderTest, TwoWayTransaction) {
Parcel data;
Parcel reply;
uint32_t handle = BinderDriverStub::GOOD_ENDPOINT;
uint32_t code = 0;
bool one_way = false;
Status status = BinderManagerInterface::Get()->Transact(handle, code, data,
&reply, one_way);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
int val;
EXPECT_TRUE(reply.ReadInt32(&val));
EXPECT_EQ(BinderDriverStub::kReplyVal, val);
std::string str;
EXPECT_TRUE(reply.ReadString(&str));
EXPECT_EQ(BinderDriverStub::kReplyString, str);
EXPECT_TRUE(reply.IsEmpty());
// Check one-way works on a call that replies with data.
status = BinderManagerInterface::Get()->Transact(handle, code, data, nullptr,
true);
EXPECT_TRUE(status);
}
TEST_F(BinderTest, TwoWayTransactionStatus) {
Parcel data;
Parcel reply;
uint32_t handle = BinderDriverStub::STATUS_ENDPOINT;
uint32_t code = 0;
bool one_way = false;
Status status = BinderManagerInterface::Get()->Transact(handle, code, data,
&reply, one_way);
ASSERT_FALSE(status);
ASSERT_TRUE(status.IsAppError());
EXPECT_EQ(BinderDriverStub::kReplyVal, status.application_status());
CheckTransaction(driver_->LastTransactionData(), handle, code, one_way);
}
TEST_F(BinderTest, Proxy) {
EXPECT_EQ(0, driver_->GetRefCount(BinderDriverStub::GOOD_ENDPOINT));
{
BinderProxy proxy(BinderDriverStub::GOOD_ENDPOINT);
EXPECT_EQ(BinderDriverStub::GOOD_ENDPOINT, proxy.handle());
EXPECT_EQ(1, driver_->GetRefCount(BinderDriverStub::GOOD_ENDPOINT));
EXPECT_TRUE(driver_->IsDeathRegistered(BinderDriverStub::GOOD_ENDPOINT,
BinderDriverStub::GOOD_ENDPOINT));
BinderProxy proxy2(BinderDriverStub::GOOD_ENDPOINT);
EXPECT_EQ(1, driver_->GetRefCount(BinderDriverStub::GOOD_ENDPOINT));
EXPECT_TRUE(driver_->IsDeathRegistered(BinderDriverStub::GOOD_ENDPOINT,
BinderDriverStub::GOOD_ENDPOINT));
}
EXPECT_EQ(0, driver_->GetRefCount(BinderDriverStub::GOOD_ENDPOINT));
}
TEST_F(BinderTest, ProxyTransaction) {
BinderProxy proxy(BinderDriverStub::GOOD_ENDPOINT);
Parcel data;
uint32_t code = 0x10;
Status status = proxy.Transact(code, &data, nullptr, true);
EXPECT_TRUE(status);
CheckTransaction(driver_->LastTransactionData(),
BinderDriverStub::GOOD_ENDPOINT, code, true);
}
TEST_F(BinderTest, ProxyDeathNotification) {
BinderProxy proxy(BinderDriverStub::GOOD_ENDPOINT);
EXPECT_FALSE(got_death_callback_);
proxy.SetDeathCallback(
base::Bind(&BinderTest::HandleBinderDeath,
weak_ptr_factory_.GetWeakPtr()));
driver_->InjectDeathNotification(BinderDriverStub::GOOD_ENDPOINT);
BinderManagerInterface::Get()->HandleEvent();
EXPECT_TRUE(got_death_callback_);
}
TEST_F(BinderTest, HostOneWay) {
EXPECT_FALSE(got_transact_callback_);
HostTest host(base::Bind(&BinderTest::HandleTransaction,
weak_ptr_factory_.GetWeakPtr()));
Parcel data;
data.WriteInt32(0xDEAD);
driver_->InjectTransaction(
host.cookie(), HostTest::GOOD_TRANSACTION, data, true);
BinderManagerInterface::Get()->HandleEvent();
EXPECT_TRUE(got_transact_callback_);
}
TEST_F(BinderTest, HostTwoWay) {
EXPECT_FALSE(got_transact_callback_);
HostTest host(base::Bind(&BinderTest::HandleTransaction,
weak_ptr_factory_.GetWeakPtr()));
Parcel data;
data.WriteInt32(0xDEAD);
driver_->InjectTransaction(
host.cookie(), HostTest::GOOD_TRANSACTION, data, false);
BinderManagerInterface::Get()->HandleEvent();
EXPECT_TRUE(got_transact_callback_);
// Unfortunately the reply data has now gone out of scope,
// but the size can still be validated.
EXPECT_EQ(sizeof(uint32_t), driver_->LastTransactionData()->data_size);
}
TEST_F(BinderTest, HostTwoWayBadStatus) {
EXPECT_FALSE(got_transact_callback_);
HostTest host(base::Bind(&BinderTest::HandleTransaction,
weak_ptr_factory_.GetWeakPtr()));
Parcel data;
data.WriteInt32(0xDEAD);
driver_->InjectTransaction(
host.cookie(), HostTest::BAD_TRANSACTION, data, false);
BinderManagerInterface::Get()->HandleEvent();
EXPECT_TRUE(got_transact_callback_);
// Check to see if status code is set.
EXPECT_EQ(TF_STATUS_CODE,
driver_->LastTransactionData()->flags & TF_STATUS_CODE);
}
} // namespace protobinder