// Copyright 2015 The Chromium 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 "base/bind.h" #include "base/files/file_util.h" #include "base/message_loop/message_loop.h" #include "base/test/test_timeouts.h" #include "chromeos/binder/command_broker.h" #include "chromeos/binder/driver.h" #include "chromeos/binder/object.h" #include "chromeos/binder/service_manager_proxy.h" #include "chromeos/binder/test_service.h" #include "chromeos/binder/transaction_data.h" #include "chromeos/binder/transaction_data_reader.h" #include "chromeos/binder/writable_transaction_data.h" #include "testing/gtest/include/gtest/gtest.h" namespace binder { class BinderEndToEndTest : public ::testing::Test { public: BinderEndToEndTest() : command_broker_(&driver_) {} void SetUp() override { ASSERT_TRUE(driver_.Initialize()); // Start the test service and get a remote object from it. ASSERT_TRUE(test_service_.StartAndWait()); remote_object_ = ServiceManagerProxy::CheckService( &command_broker_, test_service_.service_name()); ASSERT_EQ(Object::TYPE_REMOTE, remote_object_->GetType()); ASSERT_TRUE(remote_object_); } // Performs SIGNAL_TRANSACTION with a new CommandBroker instance. // Can be called from any threads. void PerformSignalTransaction() { CommandBroker command_broker(&driver_); WritableTransactionData data; data.SetCode(TestService::SIGNAL_TRANSACTION); scoped_ptr reply; ASSERT_TRUE(remote_object_->Transact(&command_broker, data, &reply)); ASSERT_TRUE(reply); TransactionDataReader reader(*reply); uint32_t code = 0; EXPECT_TRUE(reader.ReadUint32(&code)); EXPECT_EQ(TestService::SIGNAL_TRANSACTION, code); } protected: base::MessageLoopForIO message_loop_; Driver driver_; CommandBroker command_broker_; TestService test_service_; scoped_refptr remote_object_; }; TEST_F(BinderEndToEndTest, IncrementInt) { const int32_t kInput = 42; WritableTransactionData data; data.SetCode(TestService::INCREMENT_INT_TRANSACTION); data.WriteInt32(kInput); scoped_ptr reply; ASSERT_TRUE(remote_object_->Transact(&command_broker_, data, &reply)); ASSERT_TRUE(reply); TransactionDataReader reader(*reply); int32_t result = 0; EXPECT_TRUE(reader.ReadInt32(&result)); EXPECT_EQ(kInput + 1, result); } TEST_F(BinderEndToEndTest, GetFD) { WritableTransactionData data; data.SetCode(TestService::GET_FD_TRANSACTION); scoped_ptr reply; ASSERT_TRUE(remote_object_->Transact(&command_broker_, data, &reply)); ASSERT_TRUE(reply); TransactionDataReader reader(*reply); int fd = -1; EXPECT_TRUE(reader.ReadFileDescriptor(&fd)); const std::string kExpected = TestService::GetFileContents(); std::vector buf(kExpected.size()); EXPECT_TRUE(base::ReadFromFD(fd, buf.data(), buf.size())); EXPECT_EQ(kExpected, std::string(buf.data(), buf.size())); } // Tests if the multithreading is correctly supported by ensuring that the // test service can handle two transactions in parallel (i.e. handling // SIGNAL_TRANSACTION while one thread is blocked by WAIT_TRANSACTION). TEST_F(BinderEndToEndTest, MultiThread) { // Signal the object on a separate thread. base::Thread signal_thread("SignalThread"); ASSERT_TRUE(signal_thread.Start()); ASSERT_TRUE(signal_thread.WaitUntilThreadStarted()); // The use of delayed task here can result in a race if it takes long to // perform the wait transaction, but in practice it doesn't matter as it takes // only about 1 ms to perform a transaction. signal_thread.task_runner()->PostDelayedTask( FROM_HERE, base::Bind(&BinderEndToEndTest::PerformSignalTransaction, base::Unretained(this)), TestTimeouts::tiny_timeout()); // Wait for the signal. WritableTransactionData data; data.SetCode(TestService::WAIT_TRANSACTION); scoped_ptr reply; ASSERT_TRUE(remote_object_->Transact(&command_broker_, data, &reply)); ASSERT_TRUE(reply); TransactionDataReader reader(*reply); uint32_t code = 0; EXPECT_TRUE(reader.ReadUint32(&code)); EXPECT_EQ(TestService::WAIT_TRANSACTION, code); } } // namespace binder