/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <string.h> #include <initializer_list> #include <random> #include <sstream> #include <vector> #include "perfetto/ext/base/utils.h" #include "perfetto/ext/tracing/core/basic_types.h" #include "perfetto/ext/tracing/core/client_identity.h" #include "perfetto/ext/tracing/core/shared_memory_abi.h" #include "perfetto/ext/tracing/core/trace_packet.h" #include "perfetto/protozero/proto_utils.h" #include "src/base/test/vm_test_utils.h" #include "src/tracing/service/trace_buffer.h" #include "src/tracing/test/fake_packet.h" #include "test/gtest_and_gmock.h" namespace perfetto { ContainerEq; ElementsAre; IsEmpty; class TraceBufferTest : public testing::Test { … }; // ---------------------- // Main TraceBuffer tests // ---------------------- // Note for the test code: remember that the resulting size of a chunk is: // SUM(packets) + 16 (that is sizeof(ChunkRecord)). // Also remember that chunks are rounded up to 16. So, unless we are testing the // rounding logic, might be a good idea to create chunks of that size. TEST_F(TraceBufferTest, ReadWrite_EmptyBuffer) { … } // On each iteration writes a fixed-size chunk and reads it back. TEST_F(TraceBufferTest, ReadWrite_Simple) { … } TEST_F(TraceBufferTest, ReadWrite_OneChunkPerWriter) { … } // Writes chunk that up filling the buffer precisely until the end, like this: // [ c0: 512 ][ c1: 512 ][ c2: 1024 ][ c3: 2048 ] // | ---------------- 4k buffer --------------- | TEST_F(TraceBufferTest, ReadWrite_FillTillEnd) { … } // Similar to the above, but this time leaves some gap at the end and then // tries to add a chunk that doesn't fit to exercise the padding-at-end logic. // Initial condition: // [ c0: 128 ][ c1: 256 ][ c2: 512 ][ c3: 1024 ][ c4: 2048 ]{ 128 padding } // | ------------------------------- 4k buffer ------------------------------ | // // At this point we try to insert a 512 Bytes chunk (c5). The result should be: // [ c5: 512 ]{ padding }[c3: 1024 ][ c4: 2048 ]{ 128 padding } // | ------------------------------- 4k buffer ------------------------------ | TEST_F(TraceBufferTest, ReadWrite_Padding) { … } // Like ReadWrite_Padding, but this time the padding introduced is the minimum // allowed (16 bytes). This is to exercise edge cases in the padding logic. // [c0: 2048 ][c1: 1024 ][c2: 1008 ][c3: 16] // [c4: 2032 ][c5: 1040 ][c6 :16][c7: 1080 ] TEST_F(TraceBufferTest, ReadWrite_MinimalPadding) { … } TEST_F(TraceBufferTest, ReadWrite_RandomChunksNoWrapping) { … } // Tests the case of writing a chunk that leaves just sizeof(ChunkRecord) at // the end of the buffer. TEST_F(TraceBufferTest, ReadWrite_WrappingCases) { … } // Tests that when records are removed when adding padding at the end because // there is no space left. The scenario is the following: // Initial condition: [ c0: 2048 ][ c1: 2048 ] // 2nd iteration: [ c2: 2048] <-- write pointer is here // At this point we try to add a 3072 bytes chunk. It won't fit because the // space left till the end is just 2048 bytes. At this point we expect that a // padding record is added in place of c1, and c1 is removed from the index. // Final situation: [ c3: 3072 ][ PAD ] TEST_F(TraceBufferTest, ReadWrite_PaddingAtEndUpdatesIndex) { … } // Similar to ReadWrite_PaddingAtEndUpdatesIndex but makes it so that the // various chunks don't perfectly align when wrapping. TEST_F(TraceBufferTest, ReadWrite_PaddingAtEndUpdatesIndexMisaligned) { … } // Verify that empty packets are skipped. TEST_F(TraceBufferTest, ReadWrite_EmptyPacket) { … } // -------------------------------------- // Fragments stitching and skipping logic // -------------------------------------- TEST_F(TraceBufferTest, Fragments_Simple) { … } TEST_F(TraceBufferTest, Fragments_EdgeCases) { … } // The following tests verify that chunks received out-of-order are read in the // correct order. // // Fragment order {0,2,1} for sequence {1,1}, without fragmenting packets. TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMiddle) { … } // Fragment order {0,2,1} for sequence {1,1}, with fragmenting packets. TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMiddleFragmentation) { … } // Fragment order {0,2,1,3} for sequence {1,1}, with fragmenting packets. Also // verifies that another sequence isn't broken. TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMaxFragmentation) { … } // Fragment order {-2,1,-1,0} for sequence {1,1}, without fragmenting packets. TEST_F(TraceBufferTest, Fragments_OutOfOrderWithIdOverflowADCB) { … } // Fragment order {-2,0,-1,1} for sequence {1,1}, without fragmenting packets. TEST_F(TraceBufferTest, Fragments_OutOfOrderWithIdOverflowACBD) { … } TEST_F(TraceBufferTest, Fragments_EmptyChunkBefore) { … } TEST_F(TraceBufferTest, Fragments_EmptyChunkAfter) { … } // Set up a fragmented packet that happens to also have an empty chunk in the // middle of the sequence. Test that it just gets skipped. TEST_F(TraceBufferTest, Fragments_EmptyChunkInTheMiddle) { … } // Generates sequences of fragmented packets of increasing length (|seq_len|), // from [P0, P1a][P1y] to [P0, P1a][P1b][P1c]...[P1y]. Test that they are always // read as one packet. TEST_F(TraceBufferTest, Fragments_LongPackets) { … } // Similar to Fragments_LongPacket, but covers also the case of ChunkID wrapping // over its max value. TEST_F(TraceBufferTest, Fragments_LongPacketWithWrappingID) { … } TEST_F(TraceBufferTest, Fragments_PreserveUID) { … } TEST_F(TraceBufferTest, Fragments_DiscardedOnPacketSizeDropPacket) { … } TEST_F(TraceBufferTest, Fragments_IncompleteChunkNeedsPatching) { … } // -------------------------- // Out of band patching tests // -------------------------- TEST_F(TraceBufferTest, Patching_Simple) { … } TEST_F(TraceBufferTest, Patching_SkipIfChunkDoesntExist) { … } TEST_F(TraceBufferTest, Patching_AtBoundariesOfChunk) { … } // Tests kChunkNeedsPatching logic: chunks that are marked as "pending patch" // should not be read until the patch has happened. TEST_F(TraceBufferTest, Patching_ReadWaitsForPatchComplete) { … } // namespace perfetto // --------------------- // Malicious input tests // --------------------- TEST_F(TraceBufferTest, Malicious_ZeroSizedChunk) { … } // Attempting to write a chunk bigger than ChunkRecord::kMaxSize should end up // in a no-op. TEST_F(TraceBufferTest, Malicious_ChunkTooBig) { … } TEST_F(TraceBufferTest, Malicious_DeclareMorePacketsBeyondBoundaries) { … } TEST_F(TraceBufferTest, Malicious_ZeroVarintHeader) { … } // Forge a chunk where the first packet is valid but the second packet has a // varint header that continues beyond the end of the chunk (and also beyond the // end of the buffer). TEST_F(TraceBufferTest, Malicious_OverflowingVarintHeader) { … } TEST_F(TraceBufferTest, Malicious_VarintHeaderTooBig) { … } // Similar to Malicious_VarintHeaderTooBig, but this time the full chunk // contains an enormous varint number that tries to overflow. TEST_F(TraceBufferTest, Malicious_JumboVarint) { … } // Like the Malicious_ZeroVarintHeader, but put the chunk in the middle of a // sequence that would be otherwise valid. The zero-sized fragment should be // skipped. TEST_F(TraceBufferTest, Malicious_ZeroVarintHeaderInSequence) { … } // Similar to Malicious_ZeroVarintHeaderInSequence, but this time the zero-sized // fragment is the last fragment for a chunk and is marked for continuation. The // zero-sized fragment should be skipped. TEST_F(TraceBufferTest, Malicious_ZeroVarintHeaderAtEndOfChunk) { … } TEST_F(TraceBufferTest, Malicious_PatchOutOfBounds) { … } TEST_F(TraceBufferTest, Malicious_OverrideWithShorterChunkSize) { … } TEST_F(TraceBufferTest, Malicious_OverrideWithShorterChunkSizeAfterRead) { … } TEST_F(TraceBufferTest, Malicious_OverrideWithDifferentOffsetAfterRead) { … } // ------------------- // SequenceIterator tests // ------------------- TEST_F(TraceBufferTest, Iterator_OneStreamOrdered) { … } TEST_F(TraceBufferTest, Iterator_OneStreamWrapping) { … } TEST_F(TraceBufferTest, Iterator_ManyStreamsOrdered) { … } TEST_F(TraceBufferTest, Iterator_ManyStreamsWrapping) { … } // ------------------- // Re-writing same chunk id // ------------------- TEST_F(TraceBufferTest, Override_ReCommitBeforeRead) { … } TEST_F(TraceBufferTest, Override_ReCommitAfterPartialRead) { … } TEST_F(TraceBufferTest, Override_ReCommitAfterFullRead) { … } // See also the Malicious_Override* tests above. TEST_F(TraceBufferTest, Override_ReCommitInvalid) { … } TEST_F(TraceBufferTest, Override_ReCommitReordered) { … } TEST_F(TraceBufferTest, Override_ReCommitReorderedFragmenting) { … } TEST_F(TraceBufferTest, Override_ReCommitSameBeforeRead) { … } TEST_F(TraceBufferTest, Override_ReCommitSameAfterRead) { … } TEST_F(TraceBufferTest, Override_ReCommitIncompleteAfterReadOutOfOrder) { … } TEST_F(TraceBufferTest, Override_ReCommitIncompleteFragmenting) { … } TEST_F(TraceBufferTest, Override_EndOfBuffer) { … } TEST_F(TraceBufferTest, DiscardPolicy) { … } TEST_F(TraceBufferTest, MissingPacketsOnSequence) { … } TEST_F(TraceBufferTest, Clone_NoFragments) { … } TEST_F(TraceBufferTest, Clone_FragmentsOutOfOrder) { … } TEST_F(TraceBufferTest, Clone_WithPatches) { … } TEST_F(TraceBufferTest, Clone_Wrapping) { … } TEST_F(TraceBufferTest, Clone_WrappingWithPadding) { … } TEST_F(TraceBufferTest, Clone_CommitOnlyUsedSize) { … } } // namespace perfetto