1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/ipc/host_impl.h"
18
19 #include <memory>
20
21 #include "perfetto/ext/base/file_utils.h"
22 #include "perfetto/ext/base/scoped_file.h"
23 #include "perfetto/ext/base/sys_types.h"
24 #include "perfetto/ext/base/temp_file.h"
25 #include "perfetto/ext/base/unix_socket.h"
26 #include "perfetto/ext/base/utils.h"
27 #include "perfetto/ext/ipc/service.h"
28 #include "perfetto/ext/ipc/service_descriptor.h"
29 #include "src/base/test/test_task_runner.h"
30 #include "src/ipc/buffered_frame_deserializer.h"
31 #include "src/ipc/test/test_socket.h"
32 #include "test/gtest_and_gmock.h"
33
34 #include "protos/perfetto/ipc/wire_protocol.gen.h"
35 #include "src/ipc/test/client_unittest_messages.gen.h"
36
37 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
38 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
39 #include <sys/socket.h>
40 #endif
41
42 namespace perfetto {
43 namespace ipc {
44 namespace {
45
46 using ::perfetto::ipc::Frame;
47 using ::perfetto::ipc::gen::ReplyProto;
48 using ::perfetto::ipc::gen::RequestProto;
49 using ::testing::_;
50 using ::testing::Invoke;
51 using ::testing::InvokeWithoutArgs;
52 using ::testing::Return;
53
54 ipc::TestSocket kTestSocket{"host_impl_unittest"};
55
56 // RequestProto and ReplyProto are defined in client_unittest_messages.proto.
57
58 class FakeService : public Service {
59 public:
60 MOCK_METHOD(void, OnFakeMethod1, (const RequestProto&, DeferredBase*));
61
Invoker(Service * service,const ProtoMessage & req,DeferredBase deferred_reply)62 static void Invoker(Service* service,
63 const ProtoMessage& req,
64 DeferredBase deferred_reply) {
65 static_cast<FakeService*>(service)->OnFakeMethod1(
66 static_cast<const RequestProto&>(req), &deferred_reply);
67 }
68
RequestDecoder(const std::string & proto)69 static std::unique_ptr<ProtoMessage> RequestDecoder(
70 const std::string& proto) {
71 std::unique_ptr<ProtoMessage> reply(new RequestProto());
72 EXPECT_TRUE(reply->ParseFromString(proto));
73 return reply;
74 }
75
FakeService(const char * service_name)76 explicit FakeService(const char* service_name) {
77 descriptor_.service_name = service_name;
78 descriptor_.methods.push_back(
79 {"FakeMethod1", &RequestDecoder, nullptr, &Invoker});
80 }
81
GetDescriptor()82 const ServiceDescriptor& GetDescriptor() override { return descriptor_; }
83
TakeReceivedFD()84 base::ScopedFile TakeReceivedFD() { return ipc::Service::TakeReceivedFD(); }
85
86 base::ScopedFile received_fd_;
87 ServiceDescriptor descriptor_;
88 };
89
90 class FakeClient : public base::UnixSocket::EventListener {
91 public:
92 MOCK_METHOD(void, OnConnect, ());
93 MOCK_METHOD(void, OnDisconnect, ());
94 MOCK_METHOD(void, OnServiceBound, (const Frame::BindServiceReply&));
95 MOCK_METHOD(void, OnInvokeMethodReply, (const Frame::InvokeMethodReply&));
96 MOCK_METHOD(void, OnFileDescriptorReceived, (int));
97 MOCK_METHOD(void, OnRequestError, ());
98
FakeClient(base::TaskRunner * task_runner)99 explicit FakeClient(base::TaskRunner* task_runner) {
100 sock_ = base::UnixSocket::Connect(kTestSocket.name(), this, task_runner,
101 kTestSocket.family(),
102 base::SockType::kStream);
103 }
104
FakeClient(const char * sock_name,base::TaskRunner * task_runner)105 FakeClient(const char* sock_name, base::TaskRunner* task_runner) {
106 auto sock_family = base::GetSockFamily(sock_name);
107 sock_ = base::UnixSocket::Connect(sock_name, this, task_runner, sock_family,
108 base::SockType::kStream);
109 }
110
FakeClient(base::ScopedSocketHandle connected_socket,base::TaskRunner * task_runner)111 FakeClient(base::ScopedSocketHandle connected_socket,
112 base::TaskRunner* task_runner) {
113 sock_ = base::UnixSocket::AdoptConnected(std::move(connected_socket), this,
114 task_runner, kTestSocket.family(),
115 base::SockType::kStream);
116 task_runner->PostTask([this]() { OnConnect(); });
117 }
118
119 ~FakeClient() override = default;
120
BindService(const std::string & service_name)121 void BindService(const std::string& service_name) {
122 Frame frame;
123 uint64_t request_id = requests_.empty() ? 1 : requests_.rbegin()->first + 1;
124 requests_.emplace(request_id, 0);
125 frame.set_request_id(request_id);
126 frame.mutable_msg_bind_service()->set_service_name(service_name);
127 SendFrame(frame);
128 }
129
130 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
131 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
SetPeerIdentity(uid_t uid,pid_t pid,const std::string & machine_id_hint)132 void SetPeerIdentity(uid_t uid,
133 pid_t pid,
134 const std::string& machine_id_hint) {
135 Frame ipc_frame;
136 ipc_frame.set_request_id(0);
137 auto* set_peer_identity = ipc_frame.mutable_set_peer_identity();
138 set_peer_identity->set_pid(pid);
139 set_peer_identity->set_uid(static_cast<int32_t>(uid));
140 set_peer_identity->set_machine_id_hint(machine_id_hint);
141 SendFrame(ipc_frame);
142 }
143 #endif
144
InvokeMethod(ServiceID service_id,MethodID method_id,const ProtoMessage & args,bool drop_reply=false,int fd=-1)145 void InvokeMethod(ServiceID service_id,
146 MethodID method_id,
147 const ProtoMessage& args,
148 bool drop_reply = false,
149 int fd = -1) {
150 Frame frame;
151 uint64_t request_id = requests_.empty() ? 1 : requests_.rbegin()->first + 1;
152 requests_.emplace(request_id, 0);
153 frame.set_request_id(request_id);
154 frame.mutable_msg_invoke_method()->set_service_id(service_id);
155 frame.mutable_msg_invoke_method()->set_method_id(method_id);
156 frame.mutable_msg_invoke_method()->set_drop_reply(drop_reply);
157 frame.mutable_msg_invoke_method()->set_args_proto(args.SerializeAsString());
158 SendFrame(frame, fd);
159 }
160
161 // base::UnixSocket::EventListener implementation.
OnConnect(base::UnixSocket *,bool success)162 void OnConnect(base::UnixSocket*, bool success) override {
163 ASSERT_TRUE(success);
164 OnConnect();
165 }
166
OnDisconnect(base::UnixSocket *)167 void OnDisconnect(base::UnixSocket*) override { OnDisconnect(); }
168
OnDataAvailable(base::UnixSocket * sock)169 void OnDataAvailable(base::UnixSocket* sock) override {
170 ASSERT_EQ(sock_.get(), sock);
171 auto buf = frame_deserializer_.BeginReceive();
172 base::ScopedFile fd;
173 size_t rsize = sock->Receive(buf.data, buf.size, &fd);
174 ASSERT_TRUE(frame_deserializer_.EndReceive(rsize));
175 if (fd)
176 OnFileDescriptorReceived(*fd);
177 while (std::unique_ptr<Frame> frame = frame_deserializer_.PopNextFrame()) {
178 ASSERT_EQ(1u, requests_.count(frame->request_id()));
179 EXPECT_EQ(0, requests_[frame->request_id()]++);
180 if (frame->has_msg_bind_service_reply()) {
181 if (frame->msg_bind_service_reply().success())
182 last_bound_service_id_ = frame->msg_bind_service_reply().service_id();
183 return OnServiceBound(frame->msg_bind_service_reply());
184 }
185 if (frame->has_msg_invoke_method_reply())
186 return OnInvokeMethodReply(frame->msg_invoke_method_reply());
187 if (frame->has_msg_request_error())
188 return OnRequestError();
189 FAIL() << "Unexpected frame received from host";
190 }
191 }
192
SendFrame(const Frame & frame,int fd=-1)193 void SendFrame(const Frame& frame, int fd = -1) {
194 std::string buf = BufferedFrameDeserializer::Serialize(frame);
195 ASSERT_TRUE(sock_->Send(buf.data(), buf.size(), fd));
196 }
197
198 BufferedFrameDeserializer frame_deserializer_;
199 std::unique_ptr<base::UnixSocket> sock_;
200 std::map<uint64_t /* request_id */, int /* num_replies_received */> requests_;
201 ServiceID last_bound_service_id_;
202 };
203
204 class HostImplTest : public ::testing::Test {
205 public:
SetUp()206 void SetUp() override {
207 kTestSocket.Destroy();
208 task_runner_.reset(new base::TestTaskRunner());
209 #if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
210 Host* host = Host::CreateInstance_Fuchsia(task_runner_.get()).release();
211 auto socket_pair = base::UnixSocketRaw::CreatePairPosix(
212 base::SockFamily::kUnix, base::SockType::kStream);
213 host->AdoptConnectedSocket_Fuchsia(
214 base::ScopedSocketHandle(socket_pair.first.ReleaseFd()),
215 [](int) { return false; });
216 cli_.reset(
217 new FakeClient(base::ScopedSocketHandle(socket_pair.second.ReleaseFd()),
218 task_runner_.get()));
219 #else
220 Host* host =
221 Host::CreateInstance(kTestSocket.name(), task_runner_.get()).release();
222 cli_.reset(new FakeClient(task_runner_.get()));
223 #endif
224 ASSERT_NE(nullptr, host);
225 host_.reset(static_cast<HostImpl*>(host));
226 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
227 EXPECT_CALL(*cli_, OnConnect()).WillOnce(Invoke(on_connect));
228 task_runner_->RunUntilCheckpoint("on_connect");
229 }
230
TearDown()231 void TearDown() override {
232 task_runner_->RunUntilIdle();
233 cli_.reset();
234 host_.reset();
235 task_runner_->RunUntilIdle();
236 task_runner_.reset();
237 kTestSocket.Destroy();
238 }
239
240 // ::testing::StrictMock<MockEventListener> proxy_events_;
241 std::unique_ptr<base::TestTaskRunner> task_runner_;
242 std::unique_ptr<HostImpl> host_;
243 std::unique_ptr<FakeClient> cli_;
244 };
245
TEST_F(HostImplTest,BindService)246 TEST_F(HostImplTest, BindService) {
247 // First bind the service when it doesn't exists yet and check that the
248 // BindService() request fails.
249 cli_->BindService("FakeService"); // FakeService does not exist yet.
250 auto on_bind_failure = task_runner_->CreateCheckpoint("on_bind_failure");
251 EXPECT_CALL(*cli_, OnServiceBound(_))
252 .WillOnce(Invoke([on_bind_failure](const Frame::BindServiceReply& reply) {
253 ASSERT_FALSE(reply.success());
254 on_bind_failure();
255 }));
256 task_runner_->RunUntilCheckpoint("on_bind_failure");
257
258 // Now expose the service and bind it.
259 ASSERT_TRUE(host_->ExposeService(
260 std::unique_ptr<Service>(new FakeService("FakeService"))));
261 auto on_bind_success = task_runner_->CreateCheckpoint("on_bind_success");
262 cli_->BindService("FakeService");
263 EXPECT_CALL(*cli_, OnServiceBound(_))
264 .WillOnce(Invoke([on_bind_success](const Frame::BindServiceReply& reply) {
265 ASSERT_TRUE(reply.success());
266 on_bind_success();
267 }));
268 task_runner_->RunUntilCheckpoint("on_bind_success");
269 }
270
TEST_F(HostImplTest,InvokeNonExistingMethod)271 TEST_F(HostImplTest, InvokeNonExistingMethod) {
272 FakeService* fake_service = new FakeService("FakeService");
273 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
274 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
275 cli_->BindService("FakeService");
276 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
277 task_runner_->RunUntilCheckpoint("on_bind");
278
279 auto on_invoke_failure = task_runner_->CreateCheckpoint("on_invoke_failure");
280 cli_->InvokeMethod(cli_->last_bound_service_id_, 42, RequestProto());
281 EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
282 .WillOnce(
283 Invoke([on_invoke_failure](const Frame::InvokeMethodReply& reply) {
284 ASSERT_FALSE(reply.success());
285 ASSERT_FALSE(reply.has_more());
286 on_invoke_failure();
287 }));
288 task_runner_->RunUntilCheckpoint("on_invoke_failure");
289 }
290
TEST_F(HostImplTest,InvokeMethod)291 TEST_F(HostImplTest, InvokeMethod) {
292 FakeService* fake_service = new FakeService("FakeService");
293 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
294 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
295 cli_->BindService("FakeService");
296 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
297 task_runner_->RunUntilCheckpoint("on_bind");
298
299 RequestProto req_args;
300 req_args.set_data("foo");
301 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
302 auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
303 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
304 .WillOnce(
305 Invoke([on_reply_sent](const RequestProto& req, DeferredBase* reply) {
306 ASSERT_EQ("foo", req.data());
307 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
308 reply_args->set_data("bar");
309 reply->Resolve(AsyncResult<ProtoMessage>(
310 std::unique_ptr<ProtoMessage>(reply_args.release())));
311 on_reply_sent();
312 }));
313 task_runner_->RunUntilCheckpoint("on_reply_sent");
314
315 auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received");
316 EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
317 .WillOnce(
318 Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) {
319 ASSERT_TRUE(reply.success());
320 ASSERT_FALSE(reply.has_more());
321 ReplyProto reply_args;
322 reply_args.ParseFromString(reply.reply_proto());
323 ASSERT_EQ("bar", reply_args.data());
324 on_reply_received();
325 }));
326 task_runner_->RunUntilCheckpoint("on_reply_received");
327 }
328
TEST_F(HostImplTest,InvokeMethodDropReply)329 TEST_F(HostImplTest, InvokeMethodDropReply) {
330 FakeService* fake_service = new FakeService("FakeService");
331 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
332 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
333 cli_->BindService("FakeService");
334 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
335 task_runner_->RunUntilCheckpoint("on_bind");
336
337 // OnFakeMethod1 will:
338 // - Do nothing on the 1st call, when |drop_reply| == true.
339 // - Reply on the 2nd call, when |drop_reply| == false.
340 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
341 .Times(2)
342 .WillRepeatedly(Invoke([](const RequestProto& req, DeferredBase* reply) {
343 if (req.data() == "drop_reply")
344 return;
345 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
346 reply_args->set_data("the_reply");
347 reply->Resolve(AsyncResult<ProtoMessage>(
348 std::unique_ptr<ProtoMessage>(reply_args.release())));
349 }));
350
351 auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received");
352 EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
353 .WillOnce(
354 Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) {
355 ASSERT_TRUE(reply.success());
356 ReplyProto reply_args;
357 reply_args.ParseFromString(reply.reply_proto());
358 ASSERT_EQ("the_reply", reply_args.data());
359 on_reply_received();
360 }));
361
362 // Invoke the method first with |drop_reply|=true, then |drop_reply|=false.
363 RequestProto rp;
364 rp.set_data("drop_reply");
365 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, rp, true /*drop_reply*/);
366 rp.set_data("do_reply");
367 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, rp, false /*drop_reply*/);
368
369 task_runner_->RunUntilCheckpoint("on_reply_received");
370 }
371
372 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
373 !PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
374 // File descriptor sending over IPC is not supported on Windows.
TEST_F(HostImplTest,SendFileDescriptor)375 TEST_F(HostImplTest, SendFileDescriptor) {
376 FakeService* fake_service = new FakeService("FakeService");
377 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
378 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
379 cli_->BindService("FakeService");
380 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
381 task_runner_->RunUntilCheckpoint("on_bind");
382
383 static constexpr char kFileContent[] = "shared file";
384 RequestProto req_args;
385 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
386 auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
387 base::TempFile tx_file = base::TempFile::CreateUnlinked();
388 ASSERT_EQ(static_cast<size_t>(base::WriteAll(tx_file.fd(), kFileContent,
389 sizeof(kFileContent))),
390 sizeof(kFileContent));
391 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
392 .WillOnce(Invoke(
393 [on_reply_sent, &tx_file](const RequestProto&, DeferredBase* reply) {
394 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
395 auto async_res = AsyncResult<ProtoMessage>(
396 std::unique_ptr<ProtoMessage>(reply_args.release()));
397 async_res.set_fd(tx_file.fd());
398 reply->Resolve(std::move(async_res));
399 on_reply_sent();
400 }));
401 task_runner_->RunUntilCheckpoint("on_reply_sent");
402 tx_file.ReleaseFD();
403
404 auto on_fd_received = task_runner_->CreateCheckpoint("on_fd_received");
405 EXPECT_CALL(*cli_, OnFileDescriptorReceived(_))
406 .WillOnce(Invoke([on_fd_received](int fd) {
407 char buf[sizeof(kFileContent)] = {};
408 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
409 ASSERT_EQ(static_cast<int32_t>(sizeof(buf)),
410 PERFETTO_EINTR(read(fd, buf, sizeof(buf))));
411 ASSERT_STREQ(kFileContent, buf);
412 on_fd_received();
413 }));
414 EXPECT_CALL(*cli_, OnInvokeMethodReply(_));
415 task_runner_->RunUntilCheckpoint("on_fd_received");
416 }
417
TEST_F(HostImplTest,ReceiveFileDescriptor)418 TEST_F(HostImplTest, ReceiveFileDescriptor) {
419 auto received = task_runner_->CreateCheckpoint("received");
420 FakeService* fake_service = new FakeService("FakeService");
421 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
422 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
423 cli_->BindService("FakeService");
424 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
425 task_runner_->RunUntilCheckpoint("on_bind");
426
427 static constexpr char kFileContent[] = "shared file";
428 RequestProto req_args;
429 base::TempFile tx_file = base::TempFile::CreateUnlinked();
430 ASSERT_EQ(static_cast<size_t>(base::WriteAll(tx_file.fd(), kFileContent,
431 sizeof(kFileContent))),
432 sizeof(kFileContent));
433 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args, false,
434 tx_file.fd());
435 EXPECT_CALL(*cli_, OnInvokeMethodReply(_));
436 base::ScopedFile rx_fd;
437 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
438 .WillOnce(Invoke([received, &fake_service, &rx_fd](const RequestProto&,
439 DeferredBase*) {
440 rx_fd = fake_service->TakeReceivedFD();
441 received();
442 }));
443
444 task_runner_->RunUntilCheckpoint("received");
445
446 ASSERT_TRUE(rx_fd);
447 char buf[sizeof(kFileContent)] = {};
448 ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
449 ASSERT_EQ(static_cast<int32_t>(sizeof(buf)),
450 PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
451 ASSERT_STREQ(kFileContent, buf);
452 }
453 #endif // !OS_WIN
454
455 // Invoke a method and immediately after disconnect the client.
TEST_F(HostImplTest,OnClientDisconnect)456 TEST_F(HostImplTest, OnClientDisconnect) {
457 FakeService* fake_service = new FakeService("FakeService");
458 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
459 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
460 cli_->BindService("FakeService");
461 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
462 task_runner_->RunUntilCheckpoint("on_bind");
463
464 RequestProto req_args;
465 req_args.set_data("foo");
466 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
467 EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).Times(0);
468 cli_.reset(); // Disconnect the client.
469 auto on_host_method = task_runner_->CreateCheckpoint("on_host_method");
470 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
471 .WillOnce(
472 Invoke([on_host_method](const RequestProto& req, DeferredBase*) {
473 ASSERT_EQ("foo", req.data());
474 on_host_method();
475 }));
476 task_runner_->RunUntilCheckpoint("on_host_method");
477 }
478
479 // Like InvokeMethod, but instead of resolving the Deferred reply within the
480 // call stack, std::move()-s it outside an replies
TEST_F(HostImplTest,MoveReplyObjectAndReplyAsynchronously)481 TEST_F(HostImplTest, MoveReplyObjectAndReplyAsynchronously) {
482 FakeService* fake_service = new FakeService("FakeService");
483 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
484 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
485 cli_->BindService("FakeService");
486 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
487 task_runner_->RunUntilCheckpoint("on_bind");
488
489 // Invokes the remote method and waits that the FakeService sees it. The reply
490 // is not resolved but just moved into |moved_reply|.
491 RequestProto req_args;
492 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
493 auto on_invoke = task_runner_->CreateCheckpoint("on_invoke");
494 DeferredBase moved_reply;
495 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
496 .WillOnce(Invoke(
497 [on_invoke, &moved_reply](const RequestProto&, DeferredBase* reply) {
498 moved_reply = std::move(*reply);
499 on_invoke();
500 }));
501 task_runner_->RunUntilCheckpoint("on_invoke");
502
503 // Check that the FakeClient doesn't see any reply yet.
504 EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).Times(0);
505 task_runner_->RunUntilIdle();
506 ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(cli_.get()));
507
508 // Resolve the reply asynchronously in a deferred task.
509 task_runner_->PostTask([&moved_reply] {
510 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
511 reply_args->set_data("bar");
512 moved_reply.Resolve(AsyncResult<ProtoMessage>(
513 std::unique_ptr<ProtoMessage>(reply_args.release())));
514 });
515
516 auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received");
517 EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
518 .WillOnce(
519 Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) {
520 ASSERT_TRUE(reply.success());
521 ASSERT_FALSE(reply.has_more());
522 ReplyProto reply_args;
523 reply_args.ParseFromString(reply.reply_proto());
524 ASSERT_EQ("bar", reply_args.data());
525 on_reply_received();
526 }));
527 task_runner_->RunUntilCheckpoint("on_reply_received");
528 }
529
530 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
531 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
532 // Check ClientInfo of the service.
TEST_F(HostImplTest,ServiceClientInfo)533 TEST_F(HostImplTest, ServiceClientInfo) {
534 FakeService* fake_service = new FakeService("FakeService");
535 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
536 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
537 cli_->BindService("FakeService");
538 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
539 task_runner_->RunUntilCheckpoint("on_bind");
540
541 RequestProto req_args;
542 req_args.set_data("foo");
543 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
544 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
545 .WillOnce(
546 Invoke([fake_service](const RequestProto& req, DeferredBase* reply) {
547 ASSERT_EQ("foo", req.data());
548 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
549 reply_args->set_data("bar");
550 reply->Resolve(AsyncResult<ProtoMessage>(
551 std::unique_ptr<ProtoMessage>(reply_args.release())));
552 // Verifies the pid() and uid() values in ClientInfo.
553 const auto& client_info = fake_service->client_info();
554 ASSERT_EQ(client_info.uid(), getuid());
555 ASSERT_EQ(client_info.pid(), getpid());
556 }));
557
558 EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).WillOnce(Return());
559 task_runner_->RunUntilIdle();
560 }
561
TEST_F(HostImplTest,SetPeerIdentityUnixSocket)562 TEST_F(HostImplTest, SetPeerIdentityUnixSocket) {
563 FakeService* fake_service = new FakeService("FakeService");
564 ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
565 // SetPeerIdentity must be the first message. Use getpid()+1/geteuid+1 to
566 // check that this message doesn't take effect for Unix socket.
567 cli_->SetPeerIdentity(geteuid() + 1, getpid() + 1, "test_machine_id_hint");
568
569 auto on_bind = task_runner_->CreateCheckpoint("on_bind");
570 cli_->BindService("FakeService");
571 EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
572 task_runner_->RunUntilCheckpoint("on_bind");
573
574 RequestProto req_args;
575 req_args.set_data("foo");
576 cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
577 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
578 .WillOnce(
579 Invoke([fake_service](const RequestProto& req, DeferredBase* reply) {
580 ASSERT_EQ("foo", req.data());
581 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
582 reply_args->set_data("bar");
583 reply->Resolve(AsyncResult<ProtoMessage>(
584 std::unique_ptr<ProtoMessage>(reply_args.release())));
585 // Verifies the pid() and uid() values in ClientInfo.
586 const auto& client_info = fake_service->client_info();
587 ASSERT_EQ(client_info.uid(), getuid());
588 ASSERT_EQ(client_info.pid(), getpid());
589 ASSERT_EQ(client_info.machine_id(), base::kDefaultMachineID);
590 }));
591
592 EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).WillOnce(Return());
593 task_runner_->RunUntilIdle();
594 }
595
TEST(HostImpl,SetPeerIdentityTcpSocket)596 TEST(HostImpl, SetPeerIdentityTcpSocket) {
597 std::unique_ptr<base::TestTaskRunner> task_runner(new base::TestTaskRunner());
598 std::unique_ptr<HostImpl> host_impl;
599 std::unique_ptr<FakeClient> cli;
600
601 auto tear_down = base::OnScopeExit([&]() {
602 task_runner->RunUntilIdle();
603 cli.reset();
604 host_impl.reset();
605 task_runner->RunUntilIdle();
606 task_runner.reset();
607 });
608
609 Host* host = Host::CreateInstance("127.0.0.1:0", task_runner.get()).release();
610 ASSERT_NE(nullptr, host);
611 host_impl.reset(static_cast<HostImpl*>(host));
612
613 auto sock_name = host_impl->sock()->GetSockAddr();
614 cli.reset(new FakeClient(sock_name.c_str(), task_runner.get()));
615
616 auto on_connect = task_runner->CreateCheckpoint("on_connect");
617 EXPECT_CALL(*cli, OnConnect()).WillOnce(Invoke(on_connect));
618 task_runner->RunUntilCheckpoint("on_connect");
619
620 FakeService* fake_service = new FakeService("FakeService");
621 ASSERT_TRUE(host->ExposeService(std::unique_ptr<Service>(fake_service)));
622 // Set peer identity with fake values.
623 cli->SetPeerIdentity(123, 456, "test_machine_id_hint");
624
625 auto on_bind = task_runner->CreateCheckpoint("on_bind");
626 cli->BindService("FakeService");
627 EXPECT_CALL(*cli, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
628 task_runner->RunUntilCheckpoint("on_bind");
629
630 RequestProto req_args;
631 req_args.set_data("foo");
632 cli->InvokeMethod(cli->last_bound_service_id_, 1, req_args);
633 EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
634 .WillOnce(
635 Invoke([fake_service](const RequestProto& req, DeferredBase* reply) {
636 ASSERT_EQ("foo", req.data());
637 std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
638 reply_args->set_data("bar");
639 reply->Resolve(AsyncResult<ProtoMessage>(
640 std::unique_ptr<ProtoMessage>(reply_args.release())));
641 // Verify peer identity.
642 const auto& client_info = fake_service->client_info();
643 ASSERT_EQ(client_info.uid(), 123u);
644 ASSERT_EQ(client_info.pid(), 456);
645 // ClientInfo contains non-default raw machine ID.
646 ASSERT_NE(client_info.machine_id(), base::kDefaultMachineID);
647 }));
648
649 EXPECT_CALL(*cli, OnInvokeMethodReply(_)).WillOnce(Return());
650 task_runner->RunUntilIdle();
651 }
652 #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||
653 // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
654
655 // TODO(primiano): add the tests below in next CLs.
656 // TEST(HostImplTest, ManyClients) {}
657 // TEST(HostImplTest, OverlappingRequstsOutOfOrder) {}
658 // TEST(HostImplTest, StreamingRequest) {}
659 // TEST(HostImplTest, ManyDropReplyRequestsDontLeakMemory) {}
660
661 } // namespace
662 } // namespace ipc
663 } // namespace perfetto
664