• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "perfetto/base/file_utils.h"
24 #include "perfetto/base/scoped_file.h"
25 #include "perfetto/base/temp_file.h"
26 #include "perfetto/base/unix_socket.h"
27 #include "perfetto/base/utils.h"
28 #include "perfetto/ipc/service.h"
29 #include "perfetto/ipc/service_descriptor.h"
30 #include "src/base/test/test_task_runner.h"
31 #include "src/ipc/buffered_frame_deserializer.h"
32 #include "src/ipc/test/test_socket.h"
33 
34 #include "src/ipc/test/client_unittest_messages.pb.h"
35 #include "src/ipc/wire_protocol.pb.h"
36 
37 namespace perfetto {
38 namespace ipc {
39 namespace {
40 
41 using ::testing::_;
42 using ::testing::Invoke;
43 using ::testing::InvokeWithoutArgs;
44 using ::testing::Return;
45 
46 constexpr char kSockName[] = TEST_SOCK_NAME("host_impl_unittest.sock");
47 
48 // RequestProto and ReplyProto are defined in client_unittest_messages.proto.
49 
50 class FakeService : public Service {
51  public:
52   MOCK_METHOD2(OnFakeMethod1, void(const RequestProto&, DeferredBase*));
53 
Invoker(Service * service,const ProtoMessage & req,DeferredBase deferred_reply)54   static void Invoker(Service* service,
55                       const ProtoMessage& req,
56                       DeferredBase deferred_reply) {
57     static_cast<FakeService*>(service)->OnFakeMethod1(
58         static_cast<const RequestProto&>(req), &deferred_reply);
59   }
60 
RequestDecoder(const std::string & proto)61   static std::unique_ptr<ProtoMessage> RequestDecoder(
62       const std::string& proto) {
63     std::unique_ptr<ProtoMessage> reply(new RequestProto());
64     EXPECT_TRUE(reply->ParseFromString(proto));
65     return reply;
66   }
67 
FakeService(const char * service_name)68   explicit FakeService(const char* service_name) {
69     descriptor_.service_name = service_name;
70     descriptor_.methods.push_back(
71         {"FakeMethod1", &RequestDecoder, nullptr, &Invoker});
72   }
73 
GetDescriptor()74   const ServiceDescriptor& GetDescriptor() override { return descriptor_; }
75 
TakeReceivedFD()76   base::ScopedFile TakeReceivedFD() { return ipc::Service::TakeReceivedFD(); }
77 
78   base::ScopedFile received_fd_;
79   ServiceDescriptor descriptor_;
80 };
81 
82 class FakeClient : public base::UnixSocket::EventListener {
83  public:
84   MOCK_METHOD0(OnConnect, void());
85   MOCK_METHOD0(OnDisconnect, void());
86   MOCK_METHOD1(OnServiceBound, void(const Frame::BindServiceReply&));
87   MOCK_METHOD1(OnInvokeMethodReply, void(const Frame::InvokeMethodReply&));
88   MOCK_METHOD1(OnFileDescriptorReceived, void(int));
89   MOCK_METHOD0(OnRequestError, void());
90 
FakeClient(base::TaskRunner * task_runner)91   explicit FakeClient(base::TaskRunner* task_runner) {
92     sock_ = base::UnixSocket::Connect(kSockName, this, task_runner);
93   }
94 
95   ~FakeClient() override = default;
96 
BindService(const std::string & service_name)97   void BindService(const std::string& service_name) {
98     Frame frame;
99     uint64_t request_id = requests_.empty() ? 1 : requests_.rbegin()->first + 1;
100     requests_.emplace(request_id, 0);
101     frame.set_request_id(request_id);
102     frame.mutable_msg_bind_service()->set_service_name(service_name);
103     SendFrame(frame);
104   }
105 
InvokeMethod(ServiceID service_id,MethodID method_id,const ProtoMessage & args,bool drop_reply=false,int fd=-1)106   void InvokeMethod(ServiceID service_id,
107                     MethodID method_id,
108                     const ProtoMessage& args,
109                     bool drop_reply = false,
110                     int fd = -1) {
111     Frame frame;
112     uint64_t request_id = requests_.empty() ? 1 : requests_.rbegin()->first + 1;
113     requests_.emplace(request_id, 0);
114     frame.set_request_id(request_id);
115     frame.mutable_msg_invoke_method()->set_service_id(service_id);
116     frame.mutable_msg_invoke_method()->set_method_id(method_id);
117     frame.mutable_msg_invoke_method()->set_drop_reply(drop_reply);
118     frame.mutable_msg_invoke_method()->set_args_proto(args.SerializeAsString());
119     SendFrame(frame, fd);
120   }
121 
122   // base::UnixSocket::EventListener implementation.
OnConnect(base::UnixSocket *,bool success)123   void OnConnect(base::UnixSocket*, bool success) override {
124     ASSERT_TRUE(success);
125     OnConnect();
126   }
127 
OnDisconnect(base::UnixSocket *)128   void OnDisconnect(base::UnixSocket*) override { OnDisconnect(); }
129 
OnDataAvailable(base::UnixSocket * sock)130   void OnDataAvailable(base::UnixSocket* sock) override {
131     ASSERT_EQ(sock_.get(), sock);
132     auto buf = frame_deserializer_.BeginReceive();
133     base::ScopedFile fd;
134     size_t rsize = sock->Receive(buf.data, buf.size, &fd);
135     ASSERT_TRUE(frame_deserializer_.EndReceive(rsize));
136     if (fd)
137       OnFileDescriptorReceived(*fd);
138     while (std::unique_ptr<Frame> frame = frame_deserializer_.PopNextFrame()) {
139       ASSERT_EQ(1u, requests_.count(frame->request_id()));
140       EXPECT_EQ(0, requests_[frame->request_id()]++);
141       if (frame->msg_case() == Frame::kMsgBindServiceReply) {
142         if (frame->msg_bind_service_reply().success())
143           last_bound_service_id_ = frame->msg_bind_service_reply().service_id();
144         return OnServiceBound(frame->msg_bind_service_reply());
145       }
146       if (frame->msg_case() == Frame::kMsgInvokeMethodReply)
147         return OnInvokeMethodReply(frame->msg_invoke_method_reply());
148       if (frame->msg_case() == Frame::kMsgRequestError)
149         return OnRequestError();
150       FAIL() << "Unexpected frame received from host " << frame->msg_case();
151     }
152   }
153 
SendFrame(const Frame & frame,int fd=-1)154   void SendFrame(const Frame& frame, int fd = -1) {
155     std::string buf = BufferedFrameDeserializer::Serialize(frame);
156     ASSERT_TRUE(sock_->Send(buf.data(), buf.size(), fd,
157                             base::UnixSocket::BlockingMode::kBlocking));
158   }
159 
160   BufferedFrameDeserializer frame_deserializer_;
161   std::unique_ptr<base::UnixSocket> sock_;
162   std::map<uint64_t /* request_id */, int /* num_replies_received */> requests_;
163   ServiceID last_bound_service_id_;
164 };
165 
166 class HostImplTest : public ::testing::Test {
167  public:
SetUp()168   void SetUp() override {
169     DESTROY_TEST_SOCK(kSockName);
170     task_runner_.reset(new base::TestTaskRunner());
171     Host* host = Host::CreateInstance(kSockName, task_runner_.get()).release();
172     ASSERT_NE(nullptr, host);
173     host_.reset(static_cast<HostImpl*>(host));
174     cli_.reset(new FakeClient(task_runner_.get()));
175     auto on_connect = task_runner_->CreateCheckpoint("on_connect");
176     EXPECT_CALL(*cli_, OnConnect()).WillOnce(Invoke(on_connect));
177     task_runner_->RunUntilCheckpoint("on_connect");
178   }
179 
TearDown()180   void TearDown() override {
181     task_runner_->RunUntilIdle();
182     cli_.reset();
183     host_.reset();
184     task_runner_->RunUntilIdle();
185     task_runner_.reset();
186     DESTROY_TEST_SOCK(kSockName);
187   }
188 
189   // ::testing::StrictMock<MockEventListener> proxy_events_;
190   std::unique_ptr<base::TestTaskRunner> task_runner_;
191   std::unique_ptr<HostImpl> host_;
192   std::unique_ptr<FakeClient> cli_;
193 };
194 
TEST_F(HostImplTest,BindService)195 TEST_F(HostImplTest, BindService) {
196   // First bind the service when it doesn't exists yet and check that the
197   // BindService() request fails.
198   cli_->BindService("FakeService");  // FakeService does not exist yet.
199   auto on_bind_failure = task_runner_->CreateCheckpoint("on_bind_failure");
200   EXPECT_CALL(*cli_, OnServiceBound(_))
201       .WillOnce(Invoke([on_bind_failure](const Frame::BindServiceReply& reply) {
202         ASSERT_FALSE(reply.success());
203         on_bind_failure();
204       }));
205   task_runner_->RunUntilCheckpoint("on_bind_failure");
206 
207   // Now expose the service and bind it.
208   ASSERT_TRUE(host_->ExposeService(
209       std::unique_ptr<Service>(new FakeService("FakeService"))));
210   auto on_bind_success = task_runner_->CreateCheckpoint("on_bind_success");
211   cli_->BindService("FakeService");
212   EXPECT_CALL(*cli_, OnServiceBound(_))
213       .WillOnce(Invoke([on_bind_success](const Frame::BindServiceReply& reply) {
214         ASSERT_TRUE(reply.success());
215         on_bind_success();
216       }));
217   task_runner_->RunUntilCheckpoint("on_bind_success");
218 }
219 
TEST_F(HostImplTest,InvokeNonExistingMethod)220 TEST_F(HostImplTest, InvokeNonExistingMethod) {
221   FakeService* fake_service = new FakeService("FakeService");
222   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
223   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
224   cli_->BindService("FakeService");
225   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
226   task_runner_->RunUntilCheckpoint("on_bind");
227 
228   auto on_invoke_failure = task_runner_->CreateCheckpoint("on_invoke_failure");
229   cli_->InvokeMethod(cli_->last_bound_service_id_, 42, RequestProto());
230   EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
231       .WillOnce(
232           Invoke([on_invoke_failure](const Frame::InvokeMethodReply& reply) {
233             ASSERT_FALSE(reply.success());
234             ASSERT_FALSE(reply.has_more());
235             on_invoke_failure();
236           }));
237   task_runner_->RunUntilCheckpoint("on_invoke_failure");
238 }
239 
TEST_F(HostImplTest,InvokeMethod)240 TEST_F(HostImplTest, InvokeMethod) {
241   FakeService* fake_service = new FakeService("FakeService");
242   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
243   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
244   cli_->BindService("FakeService");
245   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
246   task_runner_->RunUntilCheckpoint("on_bind");
247 
248   RequestProto req_args;
249   req_args.set_data("foo");
250   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
251   auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
252   EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
253       .WillOnce(
254           Invoke([on_reply_sent](const RequestProto& req, DeferredBase* reply) {
255             ASSERT_EQ("foo", req.data());
256             std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
257             reply_args->set_data("bar");
258             reply->Resolve(AsyncResult<ProtoMessage>(
259                 std::unique_ptr<ProtoMessage>(reply_args.release())));
260             on_reply_sent();
261           }));
262   task_runner_->RunUntilCheckpoint("on_reply_sent");
263 
264   auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received");
265   EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
266       .WillOnce(
267           Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) {
268             ASSERT_TRUE(reply.success());
269             ASSERT_FALSE(reply.has_more());
270             ReplyProto reply_args;
271             reply_args.ParseFromString(reply.reply_proto());
272             ASSERT_EQ("bar", reply_args.data());
273             on_reply_received();
274           }));
275   task_runner_->RunUntilCheckpoint("on_reply_received");
276 }
277 
TEST_F(HostImplTest,InvokeMethodDropReply)278 TEST_F(HostImplTest, InvokeMethodDropReply) {
279   FakeService* fake_service = new FakeService("FakeService");
280   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
281   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
282   cli_->BindService("FakeService");
283   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
284   task_runner_->RunUntilCheckpoint("on_bind");
285 
286   // OnFakeMethod1 will:
287   // - Do nothing on the 1st call, when |drop_reply| == true.
288   // - Reply on the the 2nd call, when |drop_reply| == false.
289   EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
290       .Times(2)
291       .WillRepeatedly(Invoke([](const RequestProto& req, DeferredBase* reply) {
292         if (req.data() == "drop_reply")
293           return;
294         std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
295         reply_args->set_data("the_reply");
296         reply->Resolve(AsyncResult<ProtoMessage>(
297             std::unique_ptr<ProtoMessage>(reply_args.release())));
298       }));
299 
300   auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received");
301   EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
302       .WillOnce(
303           Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) {
304             ASSERT_TRUE(reply.success());
305             ReplyProto reply_args;
306             reply_args.ParseFromString(reply.reply_proto());
307             ASSERT_EQ("the_reply", reply_args.data());
308             on_reply_received();
309           }));
310 
311   // Invoke the method first with |drop_reply|=true, then |drop_reply|=false.
312   RequestProto rp;
313   rp.set_data("drop_reply");
314   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, rp, true /*drop_reply*/);
315   rp.set_data("do_reply");
316   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, rp, false /*drop_reply*/);
317 
318   task_runner_->RunUntilCheckpoint("on_reply_received");
319 }
320 
TEST_F(HostImplTest,SendFileDescriptor)321 TEST_F(HostImplTest, SendFileDescriptor) {
322   FakeService* fake_service = new FakeService("FakeService");
323   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
324   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
325   cli_->BindService("FakeService");
326   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
327   task_runner_->RunUntilCheckpoint("on_bind");
328 
329   static constexpr char kFileContent[] = "shared file";
330   RequestProto req_args;
331   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
332   auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
333   base::TempFile tx_file = base::TempFile::CreateUnlinked();
334   ASSERT_EQ(static_cast<size_t>(base::WriteAll(tx_file.fd(), kFileContent,
335                                                sizeof(kFileContent))),
336             sizeof(kFileContent));
337   EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
338       .WillOnce(Invoke([on_reply_sent, &tx_file](const RequestProto&,
339                                                  DeferredBase* reply) {
340         std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
341         auto async_res = AsyncResult<ProtoMessage>(
342             std::unique_ptr<ProtoMessage>(reply_args.release()));
343         async_res.set_fd(tx_file.fd());
344         reply->Resolve(std::move(async_res));
345         on_reply_sent();
346       }));
347   task_runner_->RunUntilCheckpoint("on_reply_sent");
348   tx_file.ReleaseFD();
349 
350   auto on_fd_received = task_runner_->CreateCheckpoint("on_fd_received");
351   EXPECT_CALL(*cli_, OnFileDescriptorReceived(_))
352       .WillOnce(Invoke([on_fd_received](int fd) {
353         char buf[sizeof(kFileContent)] = {};
354         ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
355         ASSERT_EQ(static_cast<int32_t>(sizeof(buf)),
356                   PERFETTO_EINTR(read(fd, buf, sizeof(buf))));
357         ASSERT_STREQ(kFileContent, buf);
358         on_fd_received();
359       }));
360   EXPECT_CALL(*cli_, OnInvokeMethodReply(_));
361   task_runner_->RunUntilCheckpoint("on_fd_received");
362 }
363 
TEST_F(HostImplTest,ReceiveFileDescriptor)364 TEST_F(HostImplTest, ReceiveFileDescriptor) {
365   auto received = task_runner_->CreateCheckpoint("received");
366   FakeService* fake_service = new FakeService("FakeService");
367   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
368   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
369   cli_->BindService("FakeService");
370   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
371   task_runner_->RunUntilCheckpoint("on_bind");
372 
373   static constexpr char kFileContent[] = "shared file";
374   RequestProto req_args;
375   base::TempFile tx_file = base::TempFile::CreateUnlinked();
376   ASSERT_EQ(static_cast<size_t>(base::WriteAll(tx_file.fd(), kFileContent,
377                                                sizeof(kFileContent))),
378             sizeof(kFileContent));
379   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args, false,
380                      tx_file.fd());
381   EXPECT_CALL(*cli_, OnInvokeMethodReply(_));
382   base::ScopedFile rx_fd;
383   EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
384       .WillOnce(Invoke([received, &fake_service, &rx_fd](const RequestProto&,
385                                                          DeferredBase*) {
386         rx_fd = fake_service->TakeReceivedFD();
387         received();
388       }));
389 
390   task_runner_->RunUntilCheckpoint("received");
391 
392   ASSERT_TRUE(rx_fd);
393   char buf[sizeof(kFileContent)] = {};
394   ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
395   ASSERT_EQ(static_cast<int32_t>(sizeof(buf)),
396             PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
397   ASSERT_STREQ(kFileContent, buf);
398 }
399 
400 // Invoke a method and immediately after disconnect the client.
TEST_F(HostImplTest,OnClientDisconnect)401 TEST_F(HostImplTest, OnClientDisconnect) {
402   FakeService* fake_service = new FakeService("FakeService");
403   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
404   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
405   cli_->BindService("FakeService");
406   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
407   task_runner_->RunUntilCheckpoint("on_bind");
408 
409   RequestProto req_args;
410   req_args.set_data("foo");
411   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
412   EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).Times(0);
413   cli_.reset();  // Disconnect the client.
414   auto on_host_method = task_runner_->CreateCheckpoint("on_host_method");
415   EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
416       .WillOnce(
417           Invoke([on_host_method](const RequestProto& req, DeferredBase*) {
418             ASSERT_EQ("foo", req.data());
419             on_host_method();
420           }));
421   task_runner_->RunUntilCheckpoint("on_host_method");
422 }
423 
424 // Like InvokeMethod, but instead of resolving the Deferred reply within the
425 // call stack, std::move()-s it outside an replies
TEST_F(HostImplTest,MoveReplyObjectAndReplyAsynchronously)426 TEST_F(HostImplTest, MoveReplyObjectAndReplyAsynchronously) {
427   FakeService* fake_service = new FakeService("FakeService");
428   ASSERT_TRUE(host_->ExposeService(std::unique_ptr<Service>(fake_service)));
429   auto on_bind = task_runner_->CreateCheckpoint("on_bind");
430   cli_->BindService("FakeService");
431   EXPECT_CALL(*cli_, OnServiceBound(_)).WillOnce(InvokeWithoutArgs(on_bind));
432   task_runner_->RunUntilCheckpoint("on_bind");
433 
434   // Invokes the remote method and waits that the FakeService sees it. The reply
435   // is not resolved but just moved into |moved_reply|.
436   RequestProto req_args;
437   cli_->InvokeMethod(cli_->last_bound_service_id_, 1, req_args);
438   auto on_invoke = task_runner_->CreateCheckpoint("on_invoke");
439   DeferredBase moved_reply;
440   EXPECT_CALL(*fake_service, OnFakeMethod1(_, _))
441       .WillOnce(Invoke(
442           [on_invoke, &moved_reply](const RequestProto&, DeferredBase* reply) {
443             moved_reply = std::move(*reply);
444             on_invoke();
445           }));
446   task_runner_->RunUntilCheckpoint("on_invoke");
447 
448   // Check that the FakeClient doesn't see any reply yet.
449   EXPECT_CALL(*cli_, OnInvokeMethodReply(_)).Times(0);
450   task_runner_->RunUntilIdle();
451   ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(cli_.get()));
452 
453   // Resolve the reply asynchronously in a deferred task.
454   task_runner_->PostTask([&moved_reply] {
455     std::unique_ptr<ReplyProto> reply_args(new ReplyProto());
456     reply_args->set_data("bar");
457     moved_reply.Resolve(AsyncResult<ProtoMessage>(
458         std::unique_ptr<ProtoMessage>(reply_args.release())));
459   });
460 
461   auto on_reply_received = task_runner_->CreateCheckpoint("on_reply_received");
462   EXPECT_CALL(*cli_, OnInvokeMethodReply(_))
463       .WillOnce(
464           Invoke([on_reply_received](const Frame::InvokeMethodReply& reply) {
465             ASSERT_TRUE(reply.success());
466             ASSERT_FALSE(reply.has_more());
467             ReplyProto reply_args;
468             reply_args.ParseFromString(reply.reply_proto());
469             ASSERT_EQ("bar", reply_args.data());
470             on_reply_received();
471           }));
472   task_runner_->RunUntilCheckpoint("on_reply_received");
473 }
474 
475 // TODO(primiano): add the tests below in next CLs.
476 // TEST(HostImplTest, ManyClients) {}
477 // TEST(HostImplTest, OverlappingRequstsOutOfOrder) {}
478 // TEST(HostImplTest, StreamingRequest) {}
479 // TEST(HostImplTest, ManyDropReplyRequestsDontLeakMemory) {}
480 
481 }  // namespace
482 }  // namespace ipc
483 }  // namespace perfetto
484