xref: /aosp_15_r20/external/perfetto/src/ipc/host_impl_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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