• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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/buffered_frame_deserializer.h"
18 
19 #include <algorithm>
20 #include <string>
21 
22 #include "gtest/gtest.h"
23 #include "perfetto/base/logging.h"
24 #include "perfetto/base/utils.h"
25 
26 #include "src/ipc/wire_protocol.pb.h"
27 
28 namespace perfetto {
29 namespace ipc {
30 namespace {
31 
32 constexpr uint32_t kHeaderSize = sizeof(uint32_t);
33 
34 // Generates a parsable Frame of exactly |size| bytes (including header).
GetSimpleFrame(size_t size)35 std::vector<char> GetSimpleFrame(size_t size) {
36   // A bit of reverse math of the proto encoding: a Frame which has only the
37   // |data_for_testing| fields, will require for each data_for_testing that is
38   // up to 127 bytes:
39   // - 1 byte to write the field preamble (field type and id).
40   // - 1 byte to write the field size, if 0 < size <= 127.
41   // - N bytes for the actual content (|padding| below).
42   // So below we split the payload into chunks of <= 127 bytes, keeping into
43   // account the extra 2 bytes for each chunk.
44   Frame frame;
45   std::vector<char> padding;
46   char padding_char = '0';
47   const uint32_t payload_size = static_cast<uint32_t>(size - kHeaderSize);
48   for (uint32_t size_left = payload_size; size_left > 0;) {
49     PERFETTO_CHECK(size_left >= 2);  // We cannot produce frames < 2 bytes.
50     uint32_t padding_size;
51     if (size_left <= 127) {
52       padding_size = size_left - 2;
53       size_left = 0;
54     } else {
55       padding_size = 124;
56       size_left -= padding_size + 2;
57     }
58     padding.resize(padding_size);
59     for (uint32_t i = 0; i < padding_size; i++) {
60       padding_char = padding_char == 'z' ? '0' : padding_char + 1;
61       padding[i] = padding_char;
62     }
63     frame.add_data_for_testing(padding.data(), padding_size);
64   }
65   PERFETTO_CHECK(frame.ByteSize() == static_cast<int>(payload_size));
66   std::vector<char> encoded_frame;
67   encoded_frame.resize(size);
68   char* enc_buf = encoded_frame.data();
69   PERFETTO_CHECK(frame.SerializeToArray(enc_buf + kHeaderSize,
70                                         static_cast<int>(payload_size)));
71   memcpy(enc_buf, base::AssumeLittleEndian(&payload_size), kHeaderSize);
72   PERFETTO_CHECK(encoded_frame.size() == size);
73   return encoded_frame;
74 }
75 
CheckedMemcpy(BufferedFrameDeserializer::ReceiveBuffer rbuf,const std::vector<char> & encoded_frame,size_t offset=0)76 void CheckedMemcpy(BufferedFrameDeserializer::ReceiveBuffer rbuf,
77                    const std::vector<char>& encoded_frame,
78                    size_t offset = 0) {
79   ASSERT_GE(rbuf.size, encoded_frame.size() + offset);
80   memcpy(rbuf.data + offset, encoded_frame.data(), encoded_frame.size());
81 }
82 
FrameEq(std::vector<char> expected_frame_with_header,const Frame & frame)83 bool FrameEq(std::vector<char> expected_frame_with_header, const Frame& frame) {
84   std::string reserialized_frame = frame.SerializeAsString();
85 
86   size_t expected_size = expected_frame_with_header.size() - kHeaderSize;
87   EXPECT_EQ(expected_size, reserialized_frame.size());
88   if (expected_size != reserialized_frame.size())
89     return false;
90 
91   return memcmp(reserialized_frame.data(),
92                 expected_frame_with_header.data() + kHeaderSize,
93                 reserialized_frame.size()) == 0;
94 }
95 
96 // Tests the simple case where each recv() just returns one whole header+frame.
TEST(BufferedFrameDeserializerTest,WholeMessages)97 TEST(BufferedFrameDeserializerTest, WholeMessages) {
98   BufferedFrameDeserializer bfd;
99   for (size_t i = 1; i <= 50; i++) {
100     const size_t size = i * 10;
101     BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
102 
103     ASSERT_NE(nullptr, rbuf.data);
104     std::vector<char> frame = GetSimpleFrame(size);
105     CheckedMemcpy(rbuf, frame);
106     ASSERT_TRUE(bfd.EndReceive(frame.size()));
107 
108     // Excactly one frame should be decoded, with no leftover buffer.
109     auto decoded_frame = bfd.PopNextFrame();
110     ASSERT_TRUE(decoded_frame);
111     ASSERT_EQ(static_cast<int32_t>(size - kHeaderSize),
112               decoded_frame->ByteSize());
113     ASSERT_FALSE(bfd.PopNextFrame());
114     ASSERT_EQ(0u, bfd.size());
115   }
116 }
117 
118 // Sends first a simple test frame. Then creates a realistic Frame fragmenting
119 // it in three chunks and tests that the decoded Frame matches the original one.
120 // The recv() sequence is as follows:
121 // 1. [ simple_frame ] [ frame_chunk1 ... ]
122 // 2. [ ... frame_chunk2 ... ]
123 // 3. [ ... frame_chunk3 ]
TEST(BufferedFrameDeserializerTest,FragmentedFrameIsCorrectlyDeserialized)124 TEST(BufferedFrameDeserializerTest, FragmentedFrameIsCorrectlyDeserialized) {
125   BufferedFrameDeserializer bfd;
126   Frame frame;
127   frame.set_request_id(42);
128   auto* bind_reply = frame.mutable_msg_bind_service_reply();
129   bind_reply->set_success(true);
130   bind_reply->set_service_id(0x4242);
131   auto* method = bind_reply->add_methods();
132   method->set_id(0x424242);
133   method->set_name("foo");
134   std::vector<char> serialized_frame;
135   uint32_t payload_size = static_cast<uint32_t>(frame.ByteSize());
136 
137   serialized_frame.resize(kHeaderSize + payload_size);
138   ASSERT_TRUE(frame.SerializeToArray(serialized_frame.data() + kHeaderSize,
139                                      static_cast<int>(payload_size)));
140   memcpy(serialized_frame.data(), base::AssumeLittleEndian(&payload_size),
141          kHeaderSize);
142 
143   std::vector<char> simple_frame = GetSimpleFrame(32);
144   std::vector<char> frame_chunk1(serialized_frame.begin(),
145                                  serialized_frame.begin() + 5);
146   BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
147   CheckedMemcpy(rbuf, simple_frame);
148   CheckedMemcpy(rbuf, frame_chunk1, simple_frame.size());
149   ASSERT_TRUE(bfd.EndReceive(simple_frame.size() + frame_chunk1.size()));
150 
151   std::vector<char> frame_chunk2(serialized_frame.begin() + 5,
152                                  serialized_frame.begin() + 10);
153   rbuf = bfd.BeginReceive();
154   CheckedMemcpy(rbuf, frame_chunk2);
155   ASSERT_TRUE(bfd.EndReceive(frame_chunk2.size()));
156 
157   std::vector<char> frame_chunk3(serialized_frame.begin() + 10,
158                                  serialized_frame.end());
159   rbuf = bfd.BeginReceive();
160   CheckedMemcpy(rbuf, frame_chunk3);
161   ASSERT_TRUE(bfd.EndReceive(frame_chunk3.size()));
162 
163   // Validate the received frame2.
164   std::unique_ptr<Frame> decoded_simple_frame = bfd.PopNextFrame();
165   ASSERT_TRUE(decoded_simple_frame);
166   ASSERT_EQ(static_cast<int32_t>(simple_frame.size() - kHeaderSize),
167             decoded_simple_frame->ByteSize());
168 
169   std::unique_ptr<Frame> decoded_frame = bfd.PopNextFrame();
170   ASSERT_TRUE(decoded_frame);
171   ASSERT_TRUE(FrameEq(serialized_frame, *decoded_frame));
172 }
173 
174 // Tests the case of a EndReceive(0) while receiving a valid frame in chunks.
TEST(BufferedFrameDeserializerTest,ZeroSizedReceive)175 TEST(BufferedFrameDeserializerTest, ZeroSizedReceive) {
176   BufferedFrameDeserializer bfd;
177   std::vector<char> frame = GetSimpleFrame(100);
178   std::vector<char> frame_chunk1(frame.begin(), frame.begin() + 50);
179   std::vector<char> frame_chunk2(frame.begin() + 50, frame.end());
180 
181   BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
182   CheckedMemcpy(rbuf, frame_chunk1);
183   ASSERT_TRUE(bfd.EndReceive(frame_chunk1.size()));
184 
185   rbuf = bfd.BeginReceive();
186   ASSERT_TRUE(bfd.EndReceive(0));
187 
188   rbuf = bfd.BeginReceive();
189   CheckedMemcpy(rbuf, frame_chunk2);
190   ASSERT_TRUE(bfd.EndReceive(frame_chunk2.size()));
191 
192   // Excactly one frame should be decoded, with no leftover buffer.
193   std::unique_ptr<Frame> decoded_frame = bfd.PopNextFrame();
194   ASSERT_TRUE(decoded_frame);
195   ASSERT_TRUE(FrameEq(frame, *decoded_frame));
196   ASSERT_FALSE(bfd.PopNextFrame());
197   ASSERT_EQ(0u, bfd.size());
198 }
199 
200 // Tests the case of a EndReceive(4) where the header has no payload. The frame
201 // should be just skipped and not returned by PopNextFrame().
TEST(BufferedFrameDeserializerTest,EmptyPayload)202 TEST(BufferedFrameDeserializerTest, EmptyPayload) {
203   BufferedFrameDeserializer bfd;
204   std::vector<char> frame = GetSimpleFrame(100);
205 
206   BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
207   std::vector<char> empty_frame(kHeaderSize, 0);
208   CheckedMemcpy(rbuf, empty_frame);
209   ASSERT_TRUE(bfd.EndReceive(kHeaderSize));
210 
211   rbuf = bfd.BeginReceive();
212   CheckedMemcpy(rbuf, frame);
213   ASSERT_TRUE(bfd.EndReceive(frame.size()));
214 
215   // |fram| should be properly decoded.
216   std::unique_ptr<Frame> decoded_frame = bfd.PopNextFrame();
217   ASSERT_TRUE(decoded_frame);
218   ASSERT_TRUE(FrameEq(frame, *decoded_frame));
219   ASSERT_FALSE(bfd.PopNextFrame());
220 }
221 
222 // Test the case where a single Receive() returns batches of > 1 whole frames.
223 // See case C in the comments for BufferedFrameDeserializer::EndReceive().
TEST(BufferedFrameDeserializerTest,MultipleFramesInOneReceive)224 TEST(BufferedFrameDeserializerTest, MultipleFramesInOneReceive) {
225   BufferedFrameDeserializer bfd;
226   std::vector<std::vector<size_t>> frame_batch_sizes(
227       {{11}, {13, 17, 19}, {23}, {29, 31}});
228 
229   for (std::vector<size_t>& batch : frame_batch_sizes) {
230     BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
231     size_t frame_offset_in_batch = 0;
232     for (size_t frame_size : batch) {
233       auto frame = GetSimpleFrame(frame_size);
234       CheckedMemcpy(rbuf, frame, frame_offset_in_batch);
235       frame_offset_in_batch += frame.size();
236     }
237     ASSERT_TRUE(bfd.EndReceive(frame_offset_in_batch));
238     for (size_t expected_size : batch) {
239       auto frame = bfd.PopNextFrame();
240       ASSERT_TRUE(frame);
241       ASSERT_EQ(static_cast<int32_t>(expected_size - kHeaderSize),
242                 frame->ByteSize());
243     }
244     ASSERT_FALSE(bfd.PopNextFrame());
245     ASSERT_EQ(0u, bfd.size());
246   }
247 }
248 
TEST(BufferedFrameDeserializerTest,RejectVeryLargeFrames)249 TEST(BufferedFrameDeserializerTest, RejectVeryLargeFrames) {
250   BufferedFrameDeserializer bfd;
251   BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
252   const uint32_t kBigSize = std::numeric_limits<uint32_t>::max() - 2;
253   memcpy(rbuf.data, base::AssumeLittleEndian(&kBigSize), kHeaderSize);
254   memcpy(rbuf.data + kHeaderSize, "some initial payload", 20);
255   ASSERT_FALSE(bfd.EndReceive(kHeaderSize + 20));
256 }
257 
258 // Tests the extreme case of recv() fragmentation. Two valid frames are received
259 // but each recv() puts one byte at a time. Covers cases A and B commented in
260 // BufferedFrameDeserializer::EndReceive().
TEST(BufferedFrameDeserializerTest,HighlyFragmentedFrames)261 TEST(BufferedFrameDeserializerTest, HighlyFragmentedFrames) {
262   BufferedFrameDeserializer bfd;
263   for (size_t i = 1; i <= 50; i++) {
264     std::vector<char> frame = GetSimpleFrame(i * 100);
265     for (size_t off = 0; off < frame.size(); off++) {
266       BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
267       CheckedMemcpy(rbuf, {frame[off]});
268 
269       // The frame should be available only when receiving the last byte.
270       ASSERT_TRUE(bfd.EndReceive(1));
271       if (off < frame.size() - 1) {
272         ASSERT_FALSE(bfd.PopNextFrame()) << off << "/" << frame.size();
273         ASSERT_EQ(off + 1, bfd.size());
274       } else {
275         ASSERT_TRUE(bfd.PopNextFrame());
276       }
277     }
278   }
279 }
280 
281 // A bunch of valid frames interleaved with frames that have a valid header
282 // but unparsable payload. The expectation is that PopNextFrame() returns
283 // nullptr for the unparsable frames but the other frames are decoded peroperly.
TEST(BufferedFrameDeserializerTest,CanRecoverAfterUnparsableFrames)284 TEST(BufferedFrameDeserializerTest, CanRecoverAfterUnparsableFrames) {
285   BufferedFrameDeserializer bfd;
286   for (size_t i = 1; i <= 50; i++) {
287     const size_t size = i * 10;
288     std::vector<char> frame = GetSimpleFrame(size);
289     const bool unparsable = (i % 3) == 1;
290     if (unparsable)
291       memset(frame.data() + kHeaderSize, 0xFF, size - kHeaderSize);
292 
293     BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
294     CheckedMemcpy(rbuf, frame);
295     ASSERT_TRUE(bfd.EndReceive(frame.size()));
296 
297     // Excactly one frame should be decoded if |parsable|. In any case no
298     // leftover bytes should be left in the buffer.
299     auto decoded_frame = bfd.PopNextFrame();
300     if (unparsable) {
301       ASSERT_FALSE(decoded_frame);
302     } else {
303       ASSERT_TRUE(decoded_frame);
304       ASSERT_EQ(static_cast<int32_t>(size - kHeaderSize),
305                 decoded_frame->ByteSize());
306     }
307     ASSERT_EQ(0u, bfd.size());
308   }
309 }
310 
311 // Test that we can sustain recvs() which constantly max out the capacity.
312 // It sets up four frames:
313 // |frame1|: small, 1024 + 4 bytes.
314 // |frame2|: as big as the |kMaxCapacity|. Its recv() is split into two chunks.
315 // |frame3|: together with the 2nd part of |frame2| it maxes out capacity again.
316 // |frame4|: as big as the |kMaxCapacity|. Received in one recv(), no splits.
317 //
318 // Which are then recv()'d in a loop in the following way.
319 //    |------------ max recv capacity ------------|
320 // 1. [       frame1      ] [ frame2_chunk1 ..... ]
321 // 2. [ ... frame2_chunk2 ]
322 // 3. [  frame3  ]
323 // 4. [               frame 4                     ]
TEST(BufferedFrameDeserializerTest,FillCapacity)324 TEST(BufferedFrameDeserializerTest, FillCapacity) {
325   size_t kMaxCapacity = 1024 * 16;
326   BufferedFrameDeserializer bfd(kMaxCapacity);
327 
328   for (int i = 0; i < 3; i++) {
329     std::vector<char> frame1 = GetSimpleFrame(1024);
330     std::vector<char> frame2 = GetSimpleFrame(kMaxCapacity);
331     std::vector<char> frame2_chunk1(
332         frame2.begin(),
333         frame2.begin() + static_cast<ptrdiff_t>(kMaxCapacity - frame1.size()));
334     std::vector<char> frame2_chunk2(
335         frame2.begin() + static_cast<ptrdiff_t>(frame2_chunk1.size()),
336         frame2.end());
337     std::vector<char> frame3 =
338         GetSimpleFrame(kMaxCapacity - frame2_chunk2.size());
339     std::vector<char> frame4 = GetSimpleFrame(kMaxCapacity);
340     ASSERT_EQ(kMaxCapacity, frame1.size() + frame2_chunk1.size());
341     ASSERT_EQ(kMaxCapacity, frame2_chunk1.size() + frame2_chunk2.size());
342     ASSERT_EQ(kMaxCapacity, frame2_chunk2.size() + frame3.size());
343     ASSERT_EQ(kMaxCapacity, frame4.size());
344 
345     BufferedFrameDeserializer::ReceiveBuffer rbuf = bfd.BeginReceive();
346     CheckedMemcpy(rbuf, frame1);
347     CheckedMemcpy(rbuf, frame2_chunk1, frame1.size());
348     ASSERT_TRUE(bfd.EndReceive(frame1.size() + frame2_chunk1.size()));
349 
350     rbuf = bfd.BeginReceive();
351     CheckedMemcpy(rbuf, frame2_chunk2);
352     ASSERT_TRUE(bfd.EndReceive(frame2_chunk2.size()));
353 
354     rbuf = bfd.BeginReceive();
355     CheckedMemcpy(rbuf, frame3);
356     ASSERT_TRUE(bfd.EndReceive(frame3.size()));
357 
358     rbuf = bfd.BeginReceive();
359     CheckedMemcpy(rbuf, frame4);
360     ASSERT_TRUE(bfd.EndReceive(frame4.size()));
361 
362     std::unique_ptr<Frame> decoded_frame_1 = bfd.PopNextFrame();
363     ASSERT_TRUE(decoded_frame_1);
364     ASSERT_TRUE(FrameEq(frame1, *decoded_frame_1));
365 
366     std::unique_ptr<Frame> decoded_frame_2 = bfd.PopNextFrame();
367     ASSERT_TRUE(decoded_frame_2);
368     ASSERT_TRUE(FrameEq(frame2, *decoded_frame_2));
369 
370     std::unique_ptr<Frame> decoded_frame_3 = bfd.PopNextFrame();
371     ASSERT_TRUE(decoded_frame_3);
372     ASSERT_TRUE(FrameEq(frame3, *decoded_frame_3));
373 
374     std::unique_ptr<Frame> decoded_frame_4 = bfd.PopNextFrame();
375     ASSERT_TRUE(decoded_frame_4);
376     ASSERT_TRUE(FrameEq(frame4, *decoded_frame_4));
377 
378     ASSERT_FALSE(bfd.PopNextFrame());
379   }
380 }
381 
382 }  // namespace
383 }  // namespace ipc
384 }  // namespace perfetto
385