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