/* * Copyright (C) 2018 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 "src/ipc/host_impl.h" #include #include "perfetto/ext/base/file_utils.h" #include "perfetto/ext/base/scoped_file.h" #include "perfetto/ext/base/sys_types.h" #include "perfetto/ext/base/temp_file.h" #include "perfetto/ext/base/unix_socket.h" #include "perfetto/ext/base/utils.h" #include "perfetto/ext/ipc/service.h" #include "perfetto/ext/ipc/service_descriptor.h" #include "src/base/test/test_task_runner.h" #include "src/ipc/buffered_frame_deserializer.h" #include "src/ipc/test/test_socket.h" #include "test/gtest_and_gmock.h" #include "protos/perfetto/ipc/wire_protocol.gen.h" #include "src/ipc/test/client_unittest_messages.gen.h" #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) #include #endif namespace perfetto { namespace ipc { namespace { using ::perfetto::ipc::Frame; using ::perfetto::ipc::gen::ReplyProto; using ::perfetto::ipc::gen::RequestProto; using ::testing::_; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; using ::testing::Return; ipc::TestSocket kTestSocket{"host_impl_unittest"}; // RequestProto and ReplyProto are defined in client_unittest_messages.proto. class FakeService : public Service { public: MOCK_METHOD(void, OnFakeMethod1, (const RequestProto&, DeferredBase*)); static void Invoker(Service* service, const ProtoMessage& req, DeferredBase deferred_reply) { static_cast(service)->OnFakeMethod1( static_cast(req), &deferred_reply); } static std::unique_ptr RequestDecoder( const std::string& proto) { std::unique_ptr reply(new RequestProto()); EXPECT_TRUE(reply->ParseFromString(proto)); return reply; } explicit FakeService(const char* service_name) { descriptor_.service_name = service_name; descriptor_.methods.push_back( {"FakeMethod1", &RequestDecoder, nullptr, &Invoker}); } const ServiceDescriptor& GetDescriptor() override { return descriptor_; } base::ScopedFile TakeReceivedFD() { return ipc::Service::TakeReceivedFD(); } base::ScopedFile received_fd_; ServiceDescriptor descriptor_; }; class FakeClient : public base::UnixSocket::EventListener { public: MOCK_METHOD(void, OnConnect, ()); MOCK_METHOD(void, OnDisconnect, ()); MOCK_METHOD(void, OnServiceBound, (const Frame::BindServiceReply&)); MOCK_METHOD(void, OnInvokeMethodReply, (const Frame::InvokeMethodReply&)); MOCK_METHOD(void, OnFileDescriptorReceived, (int)); MOCK_METHOD(void, OnRequestError, ()); explicit FakeClient(base::TaskRunner* task_runner) { sock_ = base::UnixSocket::Connect(kTestSocket.name(), this, task_runner, kTestSocket.family(), base::SockType::kStream); } FakeClient(const char* sock_name, base::TaskRunner* task_runner) { auto sock_family = base::GetSockFamily(sock_name); sock_ = base::UnixSocket::Connect(sock_name, this, task_runner, sock_family, base::SockType::kStream); } FakeClient(base::ScopedSocketHandle connected_socket, base::TaskRunner* task_runner) { sock_ = base::UnixSocket::AdoptConnected(std::move(connected_socket), this, task_runner, kTestSocket.family(), base::SockType::kStream); task_runner->PostTask([this]() { OnConnect(); }); } ~FakeClient() override = default; void BindService(const std::string& service_name) { Frame frame; uint64_t request_id = requests_.empty() ? 1 : requests_.rbegin()->first + 1; requests_.emplace(request_id, 0); frame.set_request_id(request_id); frame.mutable_msg_bind_service()->set_service_name(service_name); SendFrame(frame); } #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) void SetPeerIdentity(uid_t uid, pid_t pid, const std::string& machine_id_hint) { Frame ipc_frame; ipc_frame.set_request_id(0); auto* set_peer_identity = ipc_frame.mutable_set_peer_identity(); set_peer_identity->set_pid(pid); set_peer_identity->set_uid(static_cast(uid)); set_peer_identity->set_machine_id_hint(machine_id_hint); SendFrame(ipc_frame); } #endif void InvokeMethod(ServiceID service_id, MethodID method_id, const ProtoMessage& args, bool drop_reply = false, int fd = -1) { Frame frame; uint64_t request_id = requests_.empty() ? 1 : requests_.rbegin()->first + 1; requests_.emplace(request_id, 0); frame.set_request_id(request_id); frame.mutable_msg_invoke_method()->set_service_id(service_id); frame.mutable_msg_invoke_method()->set_method_id(method_id); frame.mutable_msg_invoke_method()->set_drop_reply(drop_reply); frame.mutable_msg_invoke_method()->set_args_proto(args.SerializeAsString()); SendFrame(frame, fd); } // base::UnixSocket::EventListener implementation. void OnConnect(base::UnixSocket*, bool success) override { ASSERT_TRUE(success); OnConnect(); } void OnDisconnect(base::UnixSocket*) override { OnDisconnect(); } void OnDataAvailable(base::UnixSocket* sock) override { ASSERT_EQ(sock_.get(), sock); auto buf = frame_deserializer_.BeginReceive(); base::ScopedFile fd; size_t rsize = sock->Receive(buf.data, buf.size, &fd); ASSERT_TRUE(frame_deserializer_.EndReceive(rsize)); if (fd) OnFileDescriptorReceived(*fd); while (std::unique_ptr frame = frame_deserializer_.PopNextFrame()) { ASSERT_EQ(1u, requests_.count(frame->request_id())); EXPECT_EQ(0, requests_[frame->request_id()]++); if (frame->has_msg_bind_service_reply()) { if (frame->msg_bind_service_reply().success()) last_bound_service_id_ = frame->msg_bind_service_reply().service_id(); return OnServiceBound(frame->msg_bind_service_reply()); } if (frame->has_msg_invoke_method_reply()) return OnInvokeMethodReply(frame->msg_invoke_method_reply()); if (frame->has_msg_request_error()) return OnRequestError(); FAIL() << "Unexpected frame received from host"; } } void SendFrame(const Frame& frame, int fd = -1) { std::string buf = BufferedFrameDeserializer::Serialize(frame); ASSERT_TRUE(sock_->Send(buf.data(), buf.size(), fd)); } BufferedFrameDeserializer frame_deserializer_; std::unique_ptr sock_; std::map requests_; ServiceID last_bound_service_id_; }; class HostImplTest : public ::testing::Test { public: void SetUp() override { kTestSocket.Destroy(); task_runner_.reset(new base::TestTaskRunner()); #if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) Host* host = Host::CreateInstance_Fuchsia(task_runner_.get()).release(); auto socket_pair = base::UnixSocketRaw::CreatePairPosix( base::SockFamily::kUnix, base::SockType::kStream); host->AdoptConnectedSocket_Fuchsia( base::ScopedSocketHandle(socket_pair.first.ReleaseFd()), [](int) { return false; }); cli_.reset( new FakeClient(base::ScopedSocketHandle(socket_pair.second.ReleaseFd()), task_runner_.get())); #else Host* host = Host::CreateInstance(kTestSocket.name(), task_runner_.get()).release(); cli_.reset(new FakeClient(task_runner_.get())); #endif ASSERT_NE(nullptr, host); host_.reset(static_cast(host)); auto on_connect = task_runner_->CreateCheckpoint("on_connect"); EXPECT_CALL(*cli_, OnConnect()).WillOnce(Invoke(on_connect)); task_runner_->RunUntilCheckpoint("on_connect"); } void TearDown() override { task_runner_->RunUntilIdle(); cli_.reset(); host_.reset(); task_runner_->RunUntilIdle(); task_runner_.reset(); kTestSocket.Destroy(); } // ::testing::StrictMock proxy_events_; std::unique_ptr task_runner_; std::unique_ptr host_; std::unique_ptr cli_; }; TEST_F(HostImplTest, BindService) { // First bind the service when it doesn't exists yet and check that the // BindService() request fails. cli_->BindService("FakeService"); // FakeService does not exist yet. auto on_bind_failure = task_runner_->CreateCheckpoint("on_bind_failure"); EXPECT_CALL(*cli_, OnServiceBound(_)) .WillOnce(Invoke([on_bind_failure](const Frame::BindServiceReply& reply) { ASSERT_FALSE(reply.success()); on_bind_failure(); })); task_runner_->RunUntilCheckpoint("on_bind_failure"); // Now expose the service and bind it. ASSERT_TRUE(host_->ExposeService( std::unique_ptr(new FakeService("FakeService")))); auto on_bind_success = task_runner_->CreateCheckpoint("on_bind_success"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)) .WillOnce(Invoke([on_bind_success](const Frame::BindServiceReply& reply) { ASSERT_TRUE(reply.success()); on_bind_success(); })); task_runner_->RunUntilCheckpoint("on_bind_success"); } TEST_F(HostImplTest, InvokeNonExistingMethod) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); auto on_invoke_failure = task_runner_->CreateCheckpoint("on_invoke_failure"); cli_->InvokeMethod(cli_->last_bound_service_id_, 42, RequestProto()); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)) .WillOnce( Invoke([on_invoke_failure](const Frame::InvokeMethodReply& reply) { ASSERT_FALSE(reply.success()); ASSERT_FALSE(reply.has_more()); on_invoke_failure(); })); task_runner_->RunUntilCheckpoint("on_invoke_failure"); } TEST_F(HostImplTest, InvokeMethod) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); RequestProto req_args; req_args.set_data("foo"); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args); auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent"); EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce( Invoke([on_reply_sent](const RequestProto& req, DeferredBase* reply) { ASSERT_EQ("foo", req.data()); std::unique_ptr reply_args(new ReplyProto()); reply_args->set_data("bar"); reply->Resolve(AsyncResult( std::unique_ptr(reply_args.release()))); on_reply_sent(); })); task_runner_->RunUntilCheckpoint("on_reply_sent"); auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received"); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)) .WillOnce( Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) { ASSERT_TRUE(reply.success()); ASSERT_FALSE(reply.has_more()); ReplyProto reply_args; reply_args.ParseFromString(reply.reply_proto()); ASSERT_EQ("bar", reply_args.data()); on_reply_received(); })); task_runner_->RunUntilCheckpoint("on_reply_received"); } TEST_F(HostImplTest, InvokeMethodDropReply) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); // OnFakeMethod1 will: // - Do nothing on the 1st call, when |drop_reply| == true. // - Reply on the 2nd call, when |drop_reply| == false. EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .Times(2) .WillRepeatedly(Invoke([](const RequestProto& req, DeferredBase* reply) { if (req.data() == "drop_reply") return; std::unique_ptr reply_args(new ReplyProto()); reply_args->set_data("the_reply"); reply->Resolve(AsyncResult( std::unique_ptr(reply_args.release()))); })); auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received"); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)) .WillOnce( Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) { ASSERT_TRUE(reply.success()); ReplyProto reply_args; reply_args.ParseFromString(reply.reply_proto()); ASSERT_EQ("the_reply", reply_args.data()); on_reply_received(); })); // Invoke the method first with |drop_reply|=true, then |drop_reply|=false. RequestProto rp; rp.set_data("drop_reply"); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, rp, true /*drop_reply*/); rp.set_data("do_reply"); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, rp, false /*drop_reply*/); task_runner_->RunUntilCheckpoint("on_reply_received"); } #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \ !PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) // File descriptor sending over IPC is not supported on Windows. TEST_F(HostImplTest, SendFileDescriptor) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); static constexpr char kFileContent[] = "shared file"; RequestProto req_args; cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args); auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent"); base::TempFile tx_file = base::TempFile::CreateUnlinked(); ASSERT_EQ(static_cast(base::WriteAll(tx_file.fd(), kFileContent, sizeof(kFileContent))), sizeof(kFileContent)); EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce(Invoke( [on_reply_sent, &tx_file](const RequestProto&, DeferredBase* reply) { std::unique_ptr reply_args(new ReplyProto()); auto async_res = AsyncResult( std::unique_ptr(reply_args.release())); async_res.set_fd(tx_file.fd()); reply->Resolve(std::move(async_res)); on_reply_sent(); })); task_runner_->RunUntilCheckpoint("on_reply_sent"); tx_file.ReleaseFD(); auto on_fd_received = task_runner_->CreateCheckpoint("on_fd_received"); EXPECT_CALL(*cli_, OnFileDescriptorReceived(_)) .WillOnce(Invoke([on_fd_received](int fd) { char buf[sizeof(kFileContent)] = {}; ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)); ASSERT_EQ(static_cast(sizeof(buf)), PERFETTO_EINTR(read(fd, buf, sizeof(buf)))); ASSERT_STREQ(kFileContent, buf); on_fd_received(); })); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)); task_runner_->RunUntilCheckpoint("on_fd_received"); } TEST_F(HostImplTest, ReceiveFileDescriptor) { auto received = task_runner_->CreateCheckpoint("received"); FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); static constexpr char kFileContent[] = "shared file"; RequestProto req_args; base::TempFile tx_file = base::TempFile::CreateUnlinked(); ASSERT_EQ(static_cast(base::WriteAll(tx_file.fd(), kFileContent, sizeof(kFileContent))), sizeof(kFileContent)); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args, false, tx_file.fd()); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)); base::ScopedFile rx_fd; EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce(Invoke([received, &fake_service, &rx_fd](const RequestProto&, DeferredBase*) { rx_fd = fake_service->TakeReceivedFD(); received(); })); task_runner_->RunUntilCheckpoint("received"); ASSERT_TRUE(rx_fd); char buf[sizeof(kFileContent)] = {}; ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET)); ASSERT_EQ(static_cast(sizeof(buf)), PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf)))); ASSERT_STREQ(kFileContent, buf); } #endif // !OS_WIN // Invoke a method and immediately after disconnect the client. TEST_F(HostImplTest, OnClientDisconnect) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); RequestProto req_args; req_args.set_data("foo"); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).Times(0); cli_.reset(); // Disconnect the client. auto on_host_method = task_runner_->CreateCheckpoint("on_host_method"); EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce( Invoke([on_host_method](const RequestProto& req, DeferredBase*) { ASSERT_EQ("foo", req.data()); on_host_method(); })); task_runner_->RunUntilCheckpoint("on_host_method"); } // Like InvokeMethod, but instead of resolving the Deferred reply within the // call stack, std::move()-s it outside an replies TEST_F(HostImplTest, MoveReplyObjectAndReplyAsynchronously) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); // Invokes the remote method and waits that the FakeService sees it. The reply // is not resolved but just moved into |moved_reply|. RequestProto req_args; cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args); auto on_invoke = task_runner_->CreateCheckpoint("on_invoke"); DeferredBase moved_reply; EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce(Invoke( [on_invoke, &moved_reply](const RequestProto&, DeferredBase* reply) { moved_reply = std::move(*reply); on_invoke(); })); task_runner_->RunUntilCheckpoint("on_invoke"); // Check that the FakeClient doesn't see any reply yet. EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).Times(0); task_runner_->RunUntilIdle(); ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(cli_.get())); // Resolve the reply asynchronously in a deferred task. task_runner_->PostTask([&moved_reply] { std::unique_ptr reply_args(new ReplyProto()); reply_args->set_data("bar"); moved_reply.Resolve(AsyncResult( std::unique_ptr(reply_args.release()))); }); auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received"); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)) .WillOnce( Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) { ASSERT_TRUE(reply.success()); ASSERT_FALSE(reply.has_more()); ReplyProto reply_args; reply_args.ParseFromString(reply.reply_proto()); ASSERT_EQ("bar", reply_args.data()); on_reply_received(); })); task_runner_->RunUntilCheckpoint("on_reply_received"); } #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) // Check ClientInfo of the service. TEST_F(HostImplTest, ServiceClientInfo) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); RequestProto req_args; req_args.set_data("foo"); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args); EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce( Invoke([fake_service](const RequestProto& req, DeferredBase* reply) { ASSERT_EQ("foo", req.data()); std::unique_ptr reply_args(new ReplyProto()); reply_args->set_data("bar"); reply->Resolve(AsyncResult( std::unique_ptr(reply_args.release()))); // Verifies the pid() and uid() values in ClientInfo. const auto& client_info = fake_service->client_info(); ASSERT_EQ(client_info.uid(), getuid()); ASSERT_EQ(client_info.pid(), getpid()); })); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).WillOnce(Return()); task_runner_->RunUntilIdle(); } TEST_F(HostImplTest, SetPeerIdentityUnixSocket) { FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host_->ExposeService(std::unique_ptr(fake_service))); // SetPeerIdentity must be the first message. Use getpid()+1/geteuid+1 to // check that this message doesn't take effect for Unix socket. cli_->SetPeerIdentity(geteuid() + 1, getpid() + 1, "test_machine_id_hint"); auto on_bind = task_runner_->CreateCheckpoint("on_bind"); cli_->BindService("FakeService"); EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner_->RunUntilCheckpoint("on_bind"); RequestProto req_args; req_args.set_data("foo"); cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args); EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce( Invoke([fake_service](const RequestProto& req, DeferredBase* reply) { ASSERT_EQ("foo", req.data()); std::unique_ptr reply_args(new ReplyProto()); reply_args->set_data("bar"); reply->Resolve(AsyncResult( std::unique_ptr(reply_args.release()))); // Verifies the pid() and uid() values in ClientInfo. const auto& client_info = fake_service->client_info(); ASSERT_EQ(client_info.uid(), getuid()); ASSERT_EQ(client_info.pid(), getpid()); ASSERT_EQ(client_info.machine_id(), base::kDefaultMachineID); })); EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).WillOnce(Return()); task_runner_->RunUntilIdle(); } TEST(HostImpl, SetPeerIdentityTcpSocket) { std::unique_ptr task_runner(new base::TestTaskRunner()); std::unique_ptr host_impl; std::unique_ptr cli; auto tear_down = base::OnScopeExit([&]() { task_runner->RunUntilIdle(); cli.reset(); host_impl.reset(); task_runner->RunUntilIdle(); task_runner.reset(); }); Host* host = Host::CreateInstance("127.0.0.1:0", task_runner.get()).release(); ASSERT_NE(nullptr, host); host_impl.reset(static_cast(host)); auto sock_name = host_impl->sock()->GetSockAddr(); cli.reset(new FakeClient(sock_name.c_str(), task_runner.get())); auto on_connect = task_runner->CreateCheckpoint("on_connect"); EXPECT_CALL(*cli, OnConnect()).WillOnce(Invoke(on_connect)); task_runner->RunUntilCheckpoint("on_connect"); FakeService* fake_service = new FakeService("FakeService"); ASSERT_TRUE(host->ExposeService(std::unique_ptr(fake_service))); // Set peer identity with fake values. cli->SetPeerIdentity(123, 456, "test_machine_id_hint"); auto on_bind = task_runner->CreateCheckpoint("on_bind"); cli->BindService("FakeService"); EXPECT_CALL(*cli, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind)); task_runner->RunUntilCheckpoint("on_bind"); RequestProto req_args; req_args.set_data("foo"); cli->InvokeMethod(cli->last_bound_service_id_, 1, req_args); EXPECT_CALL(*fake_service, OnFakeMethod1(_, _)) .WillOnce( Invoke([fake_service](const RequestProto& req, DeferredBase* reply) { ASSERT_EQ("foo", req.data()); std::unique_ptr reply_args(new ReplyProto()); reply_args->set_data("bar"); reply->Resolve(AsyncResult( std::unique_ptr(reply_args.release()))); // Verify peer identity. const auto& client_info = fake_service->client_info(); ASSERT_EQ(client_info.uid(), 123u); ASSERT_EQ(client_info.pid(), 456); // ClientInfo contains non-default raw machine ID. ASSERT_NE(client_info.machine_id(), base::kDefaultMachineID); })); EXPECT_CALL(*cli, OnInvokeMethodReply(_)).WillOnce(Return()); task_runner->RunUntilIdle(); } #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) // TODO(primiano): add the tests below in next CLs. // TEST(HostImplTest, ManyClients) {} // TEST(HostImplTest, OverlappingRequstsOutOfOrder) {} // TEST(HostImplTest, StreamingRequest) {} // TEST(HostImplTest, ManyDropReplyRequestsDontLeakMemory) {} } // namespace } // namespace ipc } // namespace perfetto