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