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
28namespace perfetto {
29namespace ipc {
30namespace {
31
32constexpr uint32_t kHeaderSize = sizeof(uint32_t);
33
34// Generates a parsable Frame of exactly |size| bytes (including header).
35std::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
76void 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
83bool 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.
97TEST(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 ]
124TEST(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.
175TEST(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().
202TEST(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().
224TEST(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
249TEST(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().
261TEST(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.
284TEST(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                     ]
324TEST(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