Home | History | Annotate | Download | only in core
      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 <string.h>
     18 
     19 #include <initializer_list>
     20 #include <random>
     21 #include <sstream>
     22 #include <vector>
     23 
     24 #include "perfetto/protozero/proto_utils.h"
     25 #include "perfetto/tracing/core/basic_types.h"
     26 #include "perfetto/tracing/core/shared_memory_abi.h"
     27 #include "perfetto/tracing/core/trace_packet.h"
     28 #include "src/tracing/core/trace_buffer.h"
     29 #include "src/tracing/test/fake_packet.h"
     30 
     31 #include "gmock/gmock.h"
     32 #include "gtest/gtest.h"
     33 
     34 namespace perfetto {
     35 
     36 using ::testing::ContainerEq;
     37 using ::testing::ElementsAre;
     38 using ::testing::IsEmpty;
     39 
     40 class TraceBufferTest : public testing::Test {
     41  public:
     42   using SequenceIterator = TraceBuffer::SequenceIterator;
     43   using ChunkMetaKey = TraceBuffer::ChunkMeta::Key;
     44   using ChunkRecord = TraceBuffer::ChunkRecord;
     45 
     46   static constexpr uint8_t kContFromPrevChunk =
     47       SharedMemoryABI::ChunkHeader::kFirstPacketContinuesFromPrevChunk;
     48   static constexpr uint8_t kContOnNextChunk =
     49       SharedMemoryABI::ChunkHeader::kLastPacketContinuesOnNextChunk;
     50   static constexpr uint8_t kChunkNeedsPatching =
     51       SharedMemoryABI::ChunkHeader::kChunkNeedsPatching;
     52 
     53   FakeChunk CreateChunk(ProducerID p, WriterID w, ChunkID c) {
     54     return FakeChunk(trace_buffer_.get(), p, w, c);
     55   }
     56 
     57   void ResetBuffer(
     58       size_t size_,
     59       TraceBuffer::OverwritePolicy policy = TraceBuffer::kOverwrite) {
     60     trace_buffer_ = TraceBuffer::Create(size_, policy);
     61     ASSERT_TRUE(trace_buffer_);
     62   }
     63 
     64   bool TryPatchChunkContents(ProducerID p,
     65                              WriterID w,
     66                              ChunkID c,
     67                              std::vector<TraceBuffer::Patch> patches,
     68                              bool other_patches_pending = false) {
     69     return trace_buffer_->TryPatchChunkContents(
     70         p, w, c, patches.data(), patches.size(), other_patches_pending);
     71   }
     72 
     73   std::vector<FakePacketFragment> ReadPacket(
     74       TraceBuffer::PacketSequenceProperties* sequence_properties = nullptr,
     75       bool* previous_packet_dropped = nullptr) {
     76     std::vector<FakePacketFragment> fragments;
     77     TracePacket packet;
     78     TraceBuffer::PacketSequenceProperties ignored_sequence_properties{};
     79     bool ignored_previous_packet_dropped;
     80     if (!trace_buffer_->ReadNextTracePacket(
     81             &packet,
     82             sequence_properties ? sequence_properties
     83                                 : &ignored_sequence_properties,
     84             previous_packet_dropped ? previous_packet_dropped
     85                                     : &ignored_previous_packet_dropped)) {
     86       return fragments;
     87     }
     88     for (const Slice& slice : packet.slices())
     89       fragments.emplace_back(slice.start, slice.size);
     90     return fragments;
     91   }
     92 
     93   void AppendChunks(
     94       std::initializer_list<std::tuple<ProducerID, WriterID, ChunkID>> chunks) {
     95     for (const auto& c : chunks) {
     96       char seed =
     97           static_cast<char>(std::get<0>(c) + std::get<1>(c) + std::get<2>(c));
     98       CreateChunk(std::get<0>(c), std::get<1>(c), std::get<2>(c))
     99           .AddPacket(4, seed)
    100           .CopyIntoTraceBuffer();
    101     }
    102   }
    103 
    104   bool IteratorSeqEq(ProducerID p,
    105                      WriterID w,
    106                      std::initializer_list<ChunkID> chunk_ids) {
    107     std::stringstream expected_seq;
    108     for (const auto& c : chunk_ids)
    109       expected_seq << "{" << p << "," << w << "," << c << "},";
    110 
    111     std::stringstream actual_seq;
    112     for (auto it = GetReadIterForSequence(p, w); it.is_valid(); it.MoveNext()) {
    113       actual_seq << "{" << it.producer_id() << "," << it.writer_id() << ","
    114                  << it.chunk_id() << "},";
    115     }
    116     std::string expected_seq_str = expected_seq.str();
    117     std::string actual_seq_str = actual_seq.str();
    118     EXPECT_EQ(expected_seq_str, actual_seq_str);
    119     return expected_seq_str == actual_seq_str;
    120   }
    121 
    122   SequenceIterator GetReadIterForSequence(ProducerID p, WriterID w) {
    123     TraceBuffer::ChunkMeta::Key key(p, w, 0);
    124     return trace_buffer_->GetReadIterForSequence(
    125         trace_buffer_->index_.lower_bound(key));
    126   }
    127 
    128   void SuppressSanityDchecksForTesting() {
    129     trace_buffer_->suppress_sanity_dchecks_for_testing_ = true;
    130   }
    131 
    132   std::vector<ChunkMetaKey> GetIndex() {
    133     std::vector<ChunkMetaKey> keys;
    134     keys.reserve(trace_buffer_->index_.size());
    135     for (const auto& it : trace_buffer_->index_)
    136       keys.push_back(it.first);
    137     return keys;
    138   }
    139 
    140   TraceBuffer* trace_buffer() { return trace_buffer_.get(); }
    141   size_t size_to_end() { return trace_buffer_->size_to_end(); }
    142 
    143  private:
    144   std::unique_ptr<TraceBuffer> trace_buffer_;
    145 };
    146 
    147 // ----------------------
    148 // Main TraceBuffer tests
    149 // ----------------------
    150 
    151 // Note for the test code: remember that the resulting size of a chunk is:
    152 // SUM(packets) + 16 (that is sizeof(ChunkRecord)).
    153 // Also remember that chunks are rounded up to 16. So, unless we are testing the
    154 // rounding logic, might be a good idea to create chunks of that size.
    155 
    156 TEST_F(TraceBufferTest, ReadWrite_EmptyBuffer) {
    157   ResetBuffer(4096);
    158   trace_buffer()->BeginRead();
    159   ASSERT_THAT(ReadPacket(), IsEmpty());
    160 }
    161 
    162 // On each iteration writes a fixed-size chunk and reads it back.
    163 TEST_F(TraceBufferTest, ReadWrite_Simple) {
    164   ResetBuffer(64 * 1024);
    165   for (ChunkID chunk_id = 0; chunk_id < 1000; chunk_id++) {
    166     char seed = static_cast<char>(chunk_id);
    167     CreateChunk(ProducerID(1), WriterID(1), chunk_id)
    168         .AddPacket(42, seed)
    169         .CopyIntoTraceBuffer();
    170     trace_buffer()->BeginRead();
    171     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(42, seed)));
    172     ASSERT_THAT(ReadPacket(), IsEmpty());
    173     EXPECT_EQ(chunk_id + 1u, trace_buffer()->stats().chunks_written());
    174     EXPECT_EQ(trace_buffer()->stats().chunks_written(),
    175               trace_buffer()->stats().chunks_read());
    176     EXPECT_LT(0u, trace_buffer()->stats().bytes_written());
    177     EXPECT_EQ(trace_buffer()->stats().bytes_written(),
    178               trace_buffer()->stats().bytes_read());
    179     EXPECT_EQ(0u, trace_buffer()->stats().padding_bytes_written());
    180     EXPECT_EQ(0u, trace_buffer()->stats().padding_bytes_cleared());
    181   }
    182 }
    183 
    184 TEST_F(TraceBufferTest, ReadWrite_OneChunkPerWriter) {
    185   for (int8_t num_writers = 1; num_writers <= 10; num_writers++) {
    186     ResetBuffer(4096);
    187     for (char i = 1; i <= num_writers; i++) {
    188       ASSERT_EQ(32u, CreateChunk(ProducerID(i), WriterID(i), ChunkID(i))
    189                          .AddPacket(32 - 16, i)
    190                          .CopyIntoTraceBuffer());
    191     }
    192 
    193     // The expected read sequence now is: c3, c4, c5.
    194     trace_buffer()->BeginRead();
    195     for (char i = 1; i <= num_writers; i++)
    196       ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32 - 16, i)));
    197     ASSERT_THAT(ReadPacket(), IsEmpty());
    198   }  // for(num_writers)
    199 }
    200 
    201 // Writes chunk that up filling the buffer precisely until the end, like this:
    202 // [ c0: 512 ][ c1: 512 ][ c2: 1024 ][ c3: 2048 ]
    203 // | ---------------- 4k buffer --------------- |
    204 TEST_F(TraceBufferTest, ReadWrite_FillTillEnd) {
    205   ResetBuffer(4096);
    206   for (int i = 0; i < 3; i++) {
    207     ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4))
    208                         .AddPacket(512 - 16, 'a')
    209                         .CopyIntoTraceBuffer());
    210     ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4 + 1))
    211                         .AddPacket(512 - 16, 'b')
    212                         .CopyIntoTraceBuffer());
    213     ASSERT_EQ(1024u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4 + 2))
    214                          .AddPacket(1024 - 16, 'c')
    215                          .CopyIntoTraceBuffer());
    216     ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4 + 3))
    217                          .AddPacket(2048 - 16, 'd')
    218                          .CopyIntoTraceBuffer());
    219 
    220     // At this point the write pointer should have been reset at the beginning.
    221     ASSERT_EQ(4096u, size_to_end());
    222 
    223     trace_buffer()->BeginRead();
    224     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(512 - 16, 'a')));
    225     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(512 - 16, 'b')));
    226     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1024 - 16, 'c')));
    227     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'd')));
    228     ASSERT_THAT(ReadPacket(), IsEmpty());
    229   }
    230 }
    231 
    232 // Similar to the above, but this time leaves some gap at the end and then
    233 // tries to add a chunk that doesn't fit to exercise the padding-at-end logic.
    234 // Initial condition:
    235 // [ c0: 128 ][ c1: 256 ][ c2: 512   ][ c3: 1024 ][ c4: 2048 ]{ 128 padding }
    236 // | ------------------------------- 4k buffer ------------------------------ |
    237 //
    238 // At this point we try to insert a 512 Bytes chunk (c5). The result should be:
    239 // [ c5: 512              ]{ padding }[c3: 1024 ][ c4: 2048 ]{ 128 padding }
    240 // | ------------------------------- 4k buffer ------------------------------ |
    241 TEST_F(TraceBufferTest, ReadWrite_Padding) {
    242   ResetBuffer(4096);
    243   ASSERT_EQ(128u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    244                       .AddPacket(128 - 16, 'a')
    245                       .CopyIntoTraceBuffer());
    246   ASSERT_EQ(256u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    247                       .AddPacket(256 - 16, 'b')
    248                       .CopyIntoTraceBuffer());
    249   ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    250                       .AddPacket(512 - 16, 'c')
    251                       .CopyIntoTraceBuffer());
    252   ASSERT_EQ(1024u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
    253                        .AddPacket(1024 - 16, 'd')
    254                        .CopyIntoTraceBuffer());
    255   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(4))
    256                        .AddPacket(2048 - 16, 'e')
    257                        .CopyIntoTraceBuffer());
    258 
    259   // Now write c5 that will cause wrapping + padding.
    260   ASSERT_EQ(128u, size_to_end());
    261   ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(5))
    262                       .AddPacket(512 - 16, 'f')
    263                       .CopyIntoTraceBuffer());
    264   ASSERT_EQ(4096u - 512, size_to_end());
    265 
    266   // The expected read sequence now is: c3, c4, c5.
    267   trace_buffer()->BeginRead();
    268   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1024 - 16, 'd')));
    269   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'e')));
    270   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(512 - 16, 'f')));
    271   ASSERT_THAT(ReadPacket(), IsEmpty());
    272 
    273   EXPECT_EQ(6u, trace_buffer()->stats().chunks_written());
    274   EXPECT_EQ(3u, trace_buffer()->stats().chunks_overwritten());
    275   EXPECT_EQ(3u, trace_buffer()->stats().chunks_read());
    276   EXPECT_EQ(4480u, trace_buffer()->stats().bytes_written());
    277   EXPECT_EQ(896u, trace_buffer()->stats().bytes_overwritten());
    278   EXPECT_EQ(3584u, trace_buffer()->stats().bytes_read());
    279   EXPECT_EQ(512u, trace_buffer()->stats().padding_bytes_written());
    280   EXPECT_EQ(0u, trace_buffer()->stats().padding_bytes_cleared());
    281 
    282   // Adding another chunk should clear some of the padding.
    283   ASSERT_EQ(128u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(6))
    284                       .AddPacket(128 - 16, 'g')
    285                       .CopyIntoTraceBuffer());
    286   EXPECT_EQ(384u, trace_buffer()->stats().padding_bytes_cleared());
    287 }
    288 
    289 // Like ReadWrite_Padding, but this time the padding introduced is the minimum
    290 // allowed (16 bytes). This is to exercise edge cases in the padding logic.
    291 // [c0: 2048               ][c1: 1024         ][c2: 1008       ][c3: 16]
    292 // [c4: 2032            ][c5: 1040                ][c6 :16][c7: 1080   ]
    293 TEST_F(TraceBufferTest, ReadWrite_MinimalPadding) {
    294   ResetBuffer(4096);
    295 
    296   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    297                        .AddPacket(2048 - 16, 'a')
    298                        .CopyIntoTraceBuffer());
    299   ASSERT_EQ(1024u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    300                        .AddPacket(1024 - 16, 'b')
    301                        .CopyIntoTraceBuffer());
    302   ASSERT_EQ(1008u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    303                        .AddPacket(1008 - 16, 'c')
    304                        .CopyIntoTraceBuffer());
    305   ASSERT_EQ(16u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
    306                      .CopyIntoTraceBuffer());
    307 
    308   ASSERT_EQ(4096u, size_to_end());
    309 
    310   ASSERT_EQ(2032u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(4))
    311                        .AddPacket(2032 - 16, 'd')
    312                        .CopyIntoTraceBuffer());
    313   ASSERT_EQ(1040u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(5))
    314                        .AddPacket(1040 - 16, 'e')
    315                        .CopyIntoTraceBuffer());
    316   ASSERT_EQ(16u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(6))
    317                      .CopyIntoTraceBuffer());
    318   ASSERT_EQ(1008u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(7))
    319                        .AddPacket(1008 - 16, 'f')
    320                        .CopyIntoTraceBuffer());
    321 
    322   ASSERT_EQ(4096u, size_to_end());
    323 
    324   // The expected read sequence now is: c3, c4, c5.
    325   trace_buffer()->BeginRead();
    326   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2032 - 16, 'd')));
    327   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1040 - 16, 'e')));
    328   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1008 - 16, 'f')));
    329   for (int i = 0; i < 3; i++)
    330     ASSERT_THAT(ReadPacket(), IsEmpty());
    331 }
    332 
    333 TEST_F(TraceBufferTest, ReadWrite_RandomChunksNoWrapping) {
    334   for (unsigned int seed = 1; seed <= 32; seed++) {
    335     std::minstd_rand0 rnd_engine(seed);
    336     ResetBuffer(4096 * (1 + rnd_engine() % 32));
    337     std::uniform_int_distribution<size_t> size_dist(18, 4096);
    338     std::uniform_int_distribution<ProducerID> prod_dist(1, kMaxProducerID);
    339     std::uniform_int_distribution<WriterID> wri_dist(1, kMaxWriterID);
    340     ChunkID chunk_id = 0;
    341     std::map<std::tuple<ProducerID, WriterID, ChunkID>, size_t> expected_chunks;
    342     for (;;) {
    343       const size_t chunk_size = size_dist(rnd_engine);
    344       if (base::AlignUp<16>(chunk_size) >= size_to_end())
    345         break;
    346       ProducerID p = prod_dist(rnd_engine);
    347       WriterID w = wri_dist(rnd_engine);
    348       ChunkID c = chunk_id++;
    349       expected_chunks.emplace(std::make_tuple(p, w, c), chunk_size);
    350       ASSERT_EQ(chunk_size,
    351                 CreateChunk(p, w, c)
    352                     .AddPacket(chunk_size - 16, static_cast<char>(chunk_size))
    353                     .CopyIntoTraceBuffer());
    354     }  // for(;;)
    355     trace_buffer()->BeginRead();
    356     for (const auto& it : expected_chunks) {
    357       const size_t chunk_size = it.second;
    358       ASSERT_THAT(ReadPacket(),
    359                   ElementsAre(FakePacketFragment(
    360                       chunk_size - 16, static_cast<char>(chunk_size))));
    361     }
    362     ASSERT_THAT(ReadPacket(), IsEmpty());
    363   }
    364 }
    365 
    366 // Tests the case of writing a chunk that leaves just sizeof(ChunkRecord) at
    367 // the end of the buffer.
    368 TEST_F(TraceBufferTest, ReadWrite_WrappingCases) {
    369   ResetBuffer(4096);
    370   ASSERT_EQ(4080u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    371                        .AddPacket(4080 - 16, 'a')
    372                        .CopyIntoTraceBuffer());
    373   trace_buffer()->BeginRead();
    374   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4080 - 16, 'a')));
    375   ASSERT_THAT(ReadPacket(), IsEmpty());
    376 
    377   ASSERT_EQ(16u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    378                      .CopyIntoTraceBuffer());
    379   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    380                        .AddPacket(2048 - 16, 'b')
    381                        .CopyIntoTraceBuffer());
    382   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
    383                        .AddPacket(2048 - 16, 'c')
    384                        .CopyIntoTraceBuffer());
    385   trace_buffer()->BeginRead();
    386   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'b')));
    387   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'c')));
    388   ASSERT_THAT(ReadPacket(), IsEmpty());
    389 }
    390 
    391 // Tests that when records are removed when adding padding at the end because
    392 // there is no space left. The scenario is the following:
    393 // Initial condition: [ c0: 2048 ][ c1: 2048 ]
    394 // 2nd iteration:     [ c2: 2048] <-- write pointer is here
    395 // At this point we try to add a 3072 bytes chunk. It won't fit because the
    396 // space left till the end is just 2048 bytes. At this point we expect that a
    397 // padding record is added in place of c1, and c1 is removed from the index.
    398 // Final situation:   [ c3: 3072     ][ PAD ]
    399 TEST_F(TraceBufferTest, ReadWrite_PaddingAtEndUpdatesIndex) {
    400   ResetBuffer(4096);
    401   // Setup initial condition: [ c0: 2048 ][ c1: 2048 ]
    402   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    403                        .AddPacket(2048 - 16, 'a')
    404                        .CopyIntoTraceBuffer());
    405   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    406                        .AddPacket(2048 - 16, 'b')
    407                        .CopyIntoTraceBuffer());
    408   ASSERT_THAT(GetIndex(),
    409               ElementsAre(ChunkMetaKey(1, 1, 0), ChunkMetaKey(1, 1, 1)));
    410 
    411   // Wrap and get to this: [ c2: 2048] <-- write pointer is here
    412   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    413                        .AddPacket(2048 - 16, 'c')
    414                        .CopyIntoTraceBuffer());
    415   ASSERT_EQ(2048u, size_to_end());
    416   ASSERT_THAT(GetIndex(),
    417               ElementsAre(ChunkMetaKey(1, 1, 1), ChunkMetaKey(1, 1, 2)));
    418 
    419   // Force wrap because of lack of space and get: [ c3: 3072     ][ PAD ].
    420   ASSERT_EQ(3072u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
    421                        .AddPacket(3072 - 16, 'd')
    422                        .CopyIntoTraceBuffer());
    423   ASSERT_THAT(GetIndex(), ElementsAre(ChunkMetaKey(1, 1, 3)));
    424 
    425   trace_buffer()->BeginRead();
    426   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(3072 - 16, 'd')));
    427   ASSERT_THAT(ReadPacket(), IsEmpty());
    428 }
    429 
    430 // Similar to ReadWrite_PaddingAtEndUpdatesIndex but makes it so that the
    431 // various chunks don't perfectly align when wrapping.
    432 TEST_F(TraceBufferTest, ReadWrite_PaddingAtEndUpdatesIndexMisaligned) {
    433   ResetBuffer(4096);
    434 
    435   // [c0: 512][c1: 512][c2: 512][c3: 512][c4: 512][c5: 512][c6: 512][c7: 512]
    436   for (char i = 0; i < 8; i++) {
    437     ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i))
    438                         .AddPacket(512 - 16, 'a' + i)
    439                         .CopyIntoTraceBuffer());
    440   }
    441   ASSERT_EQ(8u, GetIndex().size());
    442 
    443   // [c8: 2080..........................][PAD][c5: 512][c6: 512][c7: 512]
    444   //                                     ^ write pointer is here.
    445   ASSERT_EQ(2080u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(8))
    446                        .AddPacket(2080 - 16, 'i')
    447                        .CopyIntoTraceBuffer());
    448   ASSERT_EQ(2016u, size_to_end());
    449   ASSERT_THAT(GetIndex(),
    450               ElementsAre(ChunkMetaKey(1, 1, 5), ChunkMetaKey(1, 1, 6),
    451                           ChunkMetaKey(1, 1, 7), ChunkMetaKey(1, 1, 8)));
    452 
    453   // [ c9: 3104....................................][ PAD...............].
    454   ASSERT_EQ(3104u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(9))
    455                        .AddPacket(3104 - 16, 'j')
    456                        .CopyIntoTraceBuffer());
    457   ASSERT_THAT(GetIndex(), ElementsAre(ChunkMetaKey(1, 1, 9)));
    458 
    459   trace_buffer()->BeginRead();
    460   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(3104u - 16, 'j')));
    461   ASSERT_THAT(ReadPacket(), IsEmpty());
    462 }
    463 
    464 // Verify that empty packets are skipped.
    465 TEST_F(TraceBufferTest, ReadWrite_EmptyPacket) {
    466   ResetBuffer(4096);
    467   CreateChunk(ProducerID(1), WriterID(1), 0)
    468       .AddPacket(42, 1)
    469       .AddPacket(1, 2)
    470       .AddPacket(42, 3)
    471       .CopyIntoTraceBuffer();
    472 
    473   trace_buffer()->BeginRead();
    474   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(42, 1)));
    475   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(42, 3)));
    476   ASSERT_THAT(ReadPacket(), IsEmpty());
    477 
    478   EXPECT_EQ(0u, trace_buffer()->stats().abi_violations());
    479 }
    480 
    481 // --------------------------------------
    482 // Fragments stitching and skipping logic
    483 // --------------------------------------
    484 
    485 TEST_F(TraceBufferTest, Fragments_Simple) {
    486   ResetBuffer(4096);
    487   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    488       .AddPacket(10, 'a', kContFromPrevChunk)
    489       .AddPacket(20, 'b')
    490       .AddPacket(30, 'c')
    491       .AddPacket(10, 'd', kContOnNextChunk)
    492       .CopyIntoTraceBuffer();
    493   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    494       .AddPacket(20, 'e', kContFromPrevChunk)
    495       .AddPacket(30, 'f')
    496       .CopyIntoTraceBuffer();
    497 
    498   trace_buffer()->BeginRead();
    499   // The (10, 'a') entry should be skipped because we don't have provided the
    500   // previous chunk, hence should be treated as a data loss.
    501   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
    502   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
    503   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd'),
    504                                         FakePacketFragment(20, 'e')));
    505   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'f')));
    506   ASSERT_THAT(ReadPacket(), IsEmpty());
    507 }
    508 
    509 TEST_F(TraceBufferTest, Fragments_EdgeCases) {
    510   ResetBuffer(4096);
    511   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    512       .AddPacket(2, 'a', kContFromPrevChunk)
    513       .CopyIntoTraceBuffer();
    514   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    515       .AddPacket(2, 'b', kContOnNextChunk)
    516       .CopyIntoTraceBuffer();
    517   trace_buffer()->BeginRead();
    518   ASSERT_THAT(ReadPacket(), IsEmpty());
    519 
    520   // Now add the missing fragment.
    521   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    522       .AddPacket(2, 'c', kContFromPrevChunk)
    523       .CopyIntoTraceBuffer();
    524   trace_buffer()->BeginRead();
    525   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2, 'b'),
    526                                         FakePacketFragment(2, 'c')));
    527   ASSERT_THAT(ReadPacket(), IsEmpty());
    528 }
    529 
    530 // The following tests verify that chunks received out-of-order are read in the
    531 // correct order.
    532 //
    533 // Fragment order {0,2,1} for sequence {1,1}, without fragmenting packets.
    534 TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMiddle) {
    535   ResetBuffer(4096);
    536   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    537       .AddPacket(10, 'a')
    538       .CopyIntoTraceBuffer();
    539   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    540       .AddPacket(30, 'c')
    541       .CopyIntoTraceBuffer();
    542   EXPECT_EQ(0u, trace_buffer()->stats().chunks_committed_out_of_order());
    543   trace_buffer()->BeginRead();
    544   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
    545   ASSERT_THAT(ReadPacket(), IsEmpty());
    546 
    547   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    548       .AddPacket(20, 'b')
    549       .CopyIntoTraceBuffer();
    550   EXPECT_EQ(1u, trace_buffer()->stats().chunks_committed_out_of_order());
    551   trace_buffer()->BeginRead();
    552   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
    553   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
    554   ASSERT_THAT(ReadPacket(), IsEmpty());
    555 }
    556 
    557 // Fragment order {0,2,1} for sequence {1,1}, with fragmenting packets.
    558 TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMiddleFragmentation) {
    559   ResetBuffer(4096);
    560   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    561       .AddPacket(10, 'a', kContOnNextChunk)
    562       .CopyIntoTraceBuffer();
    563   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    564       .AddPacket(30, 'c', kContFromPrevChunk)
    565       .CopyIntoTraceBuffer();
    566   trace_buffer()->BeginRead();
    567   ASSERT_THAT(ReadPacket(), IsEmpty());
    568 
    569   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    570       .AddPacket(20, 'b', kContFromPrevChunk | kContOnNextChunk)
    571       .CopyIntoTraceBuffer();
    572   trace_buffer()->BeginRead();
    573   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a'),
    574                                         FakePacketFragment(20, 'b'),
    575                                         FakePacketFragment(30, 'c')));
    576   ASSERT_THAT(ReadPacket(), IsEmpty());
    577 }
    578 
    579 // Fragment order {0,2,1,3} for sequence {1,1}, with fragmenting packets. Also
    580 // verifies that another sequence isn't broken.
    581 TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMaxFragmentation) {
    582   ResetBuffer(4096);
    583   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    584       .AddPacket(10, 'a', kContOnNextChunk)
    585       .CopyIntoTraceBuffer();
    586   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    587       .AddPacket(30, 'c', kContFromPrevChunk)
    588       .CopyIntoTraceBuffer();
    589   CreateChunk(ProducerID(1), WriterID(2), ChunkID(0))
    590       .AddPacket(10, 'd')
    591       .CopyIntoTraceBuffer();
    592   trace_buffer()->BeginRead();
    593   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
    594   ASSERT_THAT(ReadPacket(), IsEmpty());
    595 
    596   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    597       .AddPacket(20, 'b', kContFromPrevChunk | kContOnNextChunk)
    598       .CopyIntoTraceBuffer();
    599   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
    600       .AddPacket(40, 'd')
    601       .CopyIntoTraceBuffer();
    602   trace_buffer()->BeginRead();
    603   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a'),
    604                                         FakePacketFragment(20, 'b'),
    605                                         FakePacketFragment(30, 'c')));
    606   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'd')));
    607   ASSERT_THAT(ReadPacket(), IsEmpty());
    608 }
    609 
    610 // Fragment order {-2,1,-1,0} for sequence {1,1}, without fragmenting packets.
    611 TEST_F(TraceBufferTest, Fragments_OutOfOrderWithIdOverflowADCB) {
    612   ResetBuffer(4096);
    613   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 1))
    614       .AddPacket(10, 'a')
    615       .CopyIntoTraceBuffer();
    616   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    617       .AddPacket(40, 'd')
    618       .CopyIntoTraceBuffer();
    619   trace_buffer()->BeginRead();
    620   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
    621   ASSERT_THAT(ReadPacket(), IsEmpty());
    622 
    623   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    624       .AddPacket(30, 'c')
    625       .CopyIntoTraceBuffer();
    626   trace_buffer()->BeginRead();
    627   ASSERT_THAT(ReadPacket(), IsEmpty());
    628 
    629   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID))
    630       .AddPacket(20, 'b')
    631       .CopyIntoTraceBuffer();
    632   trace_buffer()->BeginRead();
    633   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
    634   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
    635   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'd')));
    636   ASSERT_THAT(ReadPacket(), IsEmpty());
    637 }
    638 
    639 // Fragment order {-2,0,-1,1} for sequence {1,1}, without fragmenting packets.
    640 TEST_F(TraceBufferTest, Fragments_OutOfOrderWithIdOverflowACBD) {
    641   ResetBuffer(4096);
    642   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 1))
    643       .AddPacket(10, 'a')
    644       .CopyIntoTraceBuffer();
    645   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    646       .AddPacket(30, 'c')
    647       .CopyIntoTraceBuffer();
    648   trace_buffer()->BeginRead();
    649   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
    650   ASSERT_THAT(ReadPacket(), IsEmpty());
    651 
    652   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID))
    653       .AddPacket(20, 'b')
    654       .CopyIntoTraceBuffer();
    655   trace_buffer()->BeginRead();
    656   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
    657   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
    658   ASSERT_THAT(ReadPacket(), IsEmpty());
    659 
    660   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    661       .AddPacket(40, 'd')
    662       .CopyIntoTraceBuffer();
    663   trace_buffer()->BeginRead();
    664   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'd')));
    665   ASSERT_THAT(ReadPacket(), IsEmpty());
    666 }
    667 
    668 TEST_F(TraceBufferTest, Fragments_EmptyChunkBefore) {
    669   ResetBuffer(4096);
    670   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0)).CopyIntoTraceBuffer();
    671   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    672       .AddPacket(10, 'a')
    673       .AddPacket(20, 'b', kContOnNextChunk)
    674       .CopyIntoTraceBuffer();
    675   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    676       .AddPacket(30, 'c', kContFromPrevChunk)
    677       .AddPacket(40, 'd', kContOnNextChunk)
    678       .CopyIntoTraceBuffer();
    679   trace_buffer()->BeginRead();
    680   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
    681   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b'),
    682                                         FakePacketFragment(30, 'c')));
    683   ASSERT_THAT(ReadPacket(), IsEmpty());
    684 }
    685 
    686 TEST_F(TraceBufferTest, Fragments_EmptyChunkAfter) {
    687   ResetBuffer(4096);
    688   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    689       .AddPacket(10, 'a')
    690       .AddPacket(10, 'b', kContOnNextChunk)
    691       .CopyIntoTraceBuffer();
    692   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1)).CopyIntoTraceBuffer();
    693   trace_buffer()->BeginRead();
    694   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
    695   ASSERT_THAT(ReadPacket(), IsEmpty());
    696 }
    697 
    698 // Set up a fragmented packet that happens to also have an empty chunk in the
    699 // middle of the sequence. Test that it just gets skipped.
    700 TEST_F(TraceBufferTest, Fragments_EmptyChunkInTheMiddle) {
    701   ResetBuffer(4096);
    702   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    703       .AddPacket(10, 'a', kContOnNextChunk)
    704       .CopyIntoTraceBuffer();
    705   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1)).CopyIntoTraceBuffer();
    706   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    707       .AddPacket(10, 'b', kContFromPrevChunk)
    708       .AddPacket(20, 'c')
    709       .CopyIntoTraceBuffer();
    710   trace_buffer()->BeginRead();
    711   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a'),
    712                                         FakePacketFragment(10, 'b')));
    713   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'c')));
    714   ASSERT_THAT(ReadPacket(), IsEmpty());
    715 }
    716 
    717 // Generates sequences of fragmented packets of increasing length (|seq_len|),
    718 // from [P0, P1a][P1y] to [P0, P1a][P1b][P1c]...[P1y]. Test that they are always
    719 // read as one packet.
    720 TEST_F(TraceBufferTest, Fragments_LongPackets) {
    721   for (unsigned seq_len = 1; seq_len <= 10; seq_len++) {
    722     ResetBuffer(4096);
    723     std::vector<FakePacketFragment> expected_fragments;
    724     expected_fragments.emplace_back(20, 'b');
    725     CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    726         .AddPacket(10, 'a')
    727         .AddPacket(20, 'b', kContOnNextChunk)
    728         .CopyIntoTraceBuffer();
    729     for (unsigned i = 1; i <= seq_len; i++) {
    730       char prefix = 'b' + static_cast<char>(i);
    731       expected_fragments.emplace_back(20 + i, prefix);
    732       CreateChunk(ProducerID(1), WriterID(1), ChunkID(i))
    733           .AddPacket(20 + i, prefix, kContFromPrevChunk | kContOnNextChunk)
    734           .CopyIntoTraceBuffer();
    735     }
    736     expected_fragments.emplace_back(30, 'y');
    737     CreateChunk(ProducerID(1), WriterID(1), ChunkID(seq_len + 1))
    738         .AddPacket(30, 'y', kContFromPrevChunk)
    739         .AddPacket(50, 'z')
    740         .CopyIntoTraceBuffer();
    741 
    742     trace_buffer()->BeginRead();
    743     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
    744     ASSERT_THAT(ReadPacket(), ContainerEq(expected_fragments));
    745     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'z')));
    746     ASSERT_THAT(ReadPacket(), IsEmpty());
    747   }
    748 }
    749 
    750 // Similar to Fragments_LongPacket, but covers also the case of ChunkID wrapping
    751 // over its max value.
    752 TEST_F(TraceBufferTest, Fragments_LongPacketWithWrappingID) {
    753   ResetBuffer(4096);
    754   std::vector<FakePacketFragment> expected_fragments;
    755 
    756   for (ChunkID chunk_id = static_cast<ChunkID>(-2); chunk_id <= 2; chunk_id++) {
    757     char prefix = static_cast<char>('c' + chunk_id);
    758     expected_fragments.emplace_back(10 + chunk_id, prefix);
    759     CreateChunk(ProducerID(1), WriterID(1), chunk_id)
    760         .AddPacket(10 + chunk_id, prefix, kContOnNextChunk)
    761         .CopyIntoTraceBuffer();
    762   }
    763   trace_buffer()->BeginRead();
    764   ASSERT_THAT(ReadPacket(), ContainerEq(expected_fragments));
    765   ASSERT_THAT(ReadPacket(), IsEmpty());
    766 }
    767 
    768 TEST_F(TraceBufferTest, Fragments_PreserveUID) {
    769   ResetBuffer(4096);
    770   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    771       .AddPacket(10, 'a')
    772       .AddPacket(10, 'b', kContOnNextChunk)
    773       .SetUID(11)
    774       .CopyIntoTraceBuffer();
    775   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
    776       .AddPacket(10, 'c')
    777       .AddPacket(10, 'd')
    778       .SetUID(22)
    779       .CopyIntoTraceBuffer();
    780   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    781       .AddPacket(10, 'e', kContFromPrevChunk)
    782       .AddPacket(10, 'f')
    783       .SetUID(11)
    784       .CopyIntoTraceBuffer();
    785   trace_buffer()->BeginRead();
    786   TraceBuffer::PacketSequenceProperties sequence_properties;
    787   ASSERT_THAT(ReadPacket(&sequence_properties),
    788               ElementsAre(FakePacketFragment(10, 'a')));
    789   ASSERT_EQ(11u, sequence_properties.producer_uid_trusted);
    790 
    791   ASSERT_THAT(
    792       ReadPacket(&sequence_properties),
    793       ElementsAre(FakePacketFragment(10, 'b'), FakePacketFragment(10, 'e')));
    794   ASSERT_EQ(11u, sequence_properties.producer_uid_trusted);
    795 
    796   ASSERT_THAT(ReadPacket(&sequence_properties),
    797               ElementsAre(FakePacketFragment(10, 'f')));
    798   ASSERT_EQ(11u, sequence_properties.producer_uid_trusted);
    799 
    800   ASSERT_THAT(ReadPacket(&sequence_properties),
    801               ElementsAre(FakePacketFragment(10, 'c')));
    802   ASSERT_EQ(22u, sequence_properties.producer_uid_trusted);
    803 
    804   ASSERT_THAT(ReadPacket(&sequence_properties),
    805               ElementsAre(FakePacketFragment(10, 'd')));
    806   ASSERT_EQ(22u, sequence_properties.producer_uid_trusted);
    807 
    808   ASSERT_THAT(ReadPacket(), IsEmpty());
    809 }
    810 
    811 // --------------------------
    812 // Out of band patching tests
    813 // --------------------------
    814 
    815 TEST_F(TraceBufferTest, Patching_Simple) {
    816   ResetBuffer(4096);
    817   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    818       .AddPacket(100, 'a')
    819       .CopyIntoTraceBuffer();
    820   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
    821       .AddPacket(9, 'b')
    822       .ClearBytes(5, 4)  // 5 := 4th payload byte. Byte 0 is the varint header.
    823       .CopyIntoTraceBuffer();
    824   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
    825       .AddPacket(100, 'c')
    826       .CopyIntoTraceBuffer();
    827   ASSERT_TRUE(TryPatchChunkContents(ProducerID(2), WriterID(1), ChunkID(0),
    828                                     {{5, {{'Y', 'M', 'C', 'A'}}}}));
    829   trace_buffer()->BeginRead();
    830   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'a')));
    831   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment("b00-YMCA", 8)));
    832   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'c')));
    833   ASSERT_THAT(ReadPacket(), IsEmpty());
    834 }
    835 
    836 TEST_F(TraceBufferTest, Patching_SkipIfChunkDoesntExist) {
    837   ResetBuffer(4096);
    838   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    839       .AddPacket(100, 'a')
    840       .CopyIntoTraceBuffer();
    841   ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(2), ChunkID(0),
    842                                      {{0, {{'X', 'X', 'X', 'X'}}}}));
    843   ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(1), ChunkID(1),
    844                                      {{0, {{'X', 'X', 'X', 'X'}}}}));
    845   ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(1), ChunkID(-1),
    846                                      {{0, {{'X', 'X', 'X', 'X'}}}}));
    847   trace_buffer()->BeginRead();
    848   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'a')));
    849   ASSERT_THAT(ReadPacket(), IsEmpty());
    850 }
    851 
    852 TEST_F(TraceBufferTest, Patching_AtBoundariesOfChunk) {
    853   ResetBuffer(4096);
    854   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    855       .AddPacket(100, 'a', kContOnNextChunk)
    856       .CopyIntoTraceBuffer();
    857   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    858       .AddPacket(16, 'b', kContFromPrevChunk | kContOnNextChunk)
    859       .ClearBytes(1, 4)
    860       .ClearBytes(16 - 4, 4)
    861       .CopyIntoTraceBuffer();
    862   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    863       .AddPacket(100, 'c', kContFromPrevChunk)
    864       .CopyIntoTraceBuffer();
    865   ASSERT_TRUE(TryPatchChunkContents(
    866       ProducerID(1), WriterID(1), ChunkID(1),
    867       {{1, {{'P', 'E', 'R', 'F'}}}, {16 - 4, {{'E', 'T', 'T', 'O'}}}}));
    868   trace_buffer()->BeginRead();
    869   ASSERT_THAT(ReadPacket(),
    870               ElementsAre(FakePacketFragment(100, 'a'),
    871                           FakePacketFragment("PERFb01-b02ETTO", 15),
    872                           FakePacketFragment(100, 'c')));
    873   ASSERT_THAT(ReadPacket(), IsEmpty());
    874 }
    875 
    876 // Tests kChunkNeedsPatching logic: chunks that are marked as "pending patch"
    877 // should not be read until the patch has happened.
    878 TEST_F(TraceBufferTest, Patching_ReadWaitsForPatchComplete) {
    879   ResetBuffer(4096);
    880 
    881   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    882       .AddPacket(16, 'a', kChunkNeedsPatching)
    883       .ClearBytes(1, 4)  // 1 := 0th payload byte. Byte 0 is the varint header.
    884       .CopyIntoTraceBuffer();
    885   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
    886       .AddPacket(16, 'b')
    887       .CopyIntoTraceBuffer();
    888 
    889   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
    890       .AddPacket(16, 'c')
    891       .CopyIntoTraceBuffer();
    892   CreateChunk(ProducerID(2), WriterID(1), ChunkID(1))
    893       .AddPacket(16, 'd', kChunkNeedsPatching)
    894       .ClearBytes(1, 4)  // 1 := 0th payload byte. Byte 0 is the varint header.
    895       .CopyIntoTraceBuffer();
    896   CreateChunk(ProducerID(2), WriterID(1), ChunkID(2))
    897       .AddPacket(16, 'e')
    898       .CopyIntoTraceBuffer();
    899 
    900   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
    901       .AddPacket(16, 'f', kChunkNeedsPatching)
    902       .ClearBytes(1, 8)  // 1 := 0th payload byte. Byte 0 is the varint header.
    903       .CopyIntoTraceBuffer();
    904 
    905   // The only thing that can be read right now is the 1st packet of the 2nd
    906   // sequence. All the rest is blocked waiting for patching.
    907   trace_buffer()->BeginRead();
    908   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(16, 'c')));
    909   ASSERT_THAT(ReadPacket(), IsEmpty());
    910 
    911   // Now patch the 2nd sequence and check that the sequence is unblocked.
    912   ASSERT_TRUE(TryPatchChunkContents(ProducerID(2), WriterID(1), ChunkID(1),
    913                                     {{1, {{'P', 'A', 'T', 'C'}}}}));
    914   trace_buffer()->BeginRead();
    915   ASSERT_THAT(ReadPacket(),
    916               ElementsAre(FakePacketFragment("PATCd01-d02-d03", 15)));
    917   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(16, 'e')));
    918   ASSERT_THAT(ReadPacket(), IsEmpty());
    919 
    920   // Now patch the 3rd sequence, but in the first patch set
    921   // |other_patches_pending| to true, so that the sequence is unblocked only
    922   // after the 2nd patch.
    923   ASSERT_TRUE(TryPatchChunkContents(ProducerID(3), WriterID(1), ChunkID(0),
    924                                     {{1, {{'P', 'E', 'R', 'F'}}}},
    925                                     /*other_patches_pending=*/true));
    926   trace_buffer()->BeginRead();
    927   ASSERT_THAT(ReadPacket(), IsEmpty());
    928 
    929   ASSERT_TRUE(TryPatchChunkContents(ProducerID(3), WriterID(1), ChunkID(0),
    930                                     {{5, {{'E', 'T', 'T', 'O'}}}},
    931                                     /*other_patches_pending=*/false));
    932   trace_buffer()->BeginRead();
    933   ASSERT_THAT(ReadPacket(),
    934               ElementsAre(FakePacketFragment("PERFETTOf02-f03", 15)));
    935   ASSERT_THAT(ReadPacket(), IsEmpty());
    936 
    937 }  // namespace perfetto
    938 
    939 // ---------------------
    940 // Malicious input tests
    941 // ---------------------
    942 
    943 TEST_F(TraceBufferTest, Malicious_ZeroSizedChunk) {
    944   ResetBuffer(4096);
    945   SuppressSanityDchecksForTesting();
    946   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    947       .AddPacket(32, 'a')
    948       .CopyIntoTraceBuffer();
    949 
    950   uint8_t valid_ptr = 0;
    951   trace_buffer()->CopyChunkUntrusted(
    952       ProducerID(1), uid_t(0), WriterID(1), ChunkID(1), 1 /* num packets */,
    953       0 /* flags */, true /* chunk_complete */, &valid_ptr, sizeof(valid_ptr));
    954 
    955   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
    956       .AddPacket(32, 'b')
    957       .CopyIntoTraceBuffer();
    958 
    959   trace_buffer()->BeginRead();
    960   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'a')));
    961   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'b')));
    962   ASSERT_THAT(ReadPacket(), IsEmpty());
    963 }
    964 
    965 // Attempting to write a chunk bigger than ChunkRecord::kMaxSize should end up
    966 // in a no-op.
    967 TEST_F(TraceBufferTest, Malicious_ChunkTooBig) {
    968   ResetBuffer(4096);
    969   SuppressSanityDchecksForTesting();
    970   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    971       .AddPacket(4096, 'a')
    972       .AddPacket(2048, 'b')
    973       .CopyIntoTraceBuffer();
    974   trace_buffer()->BeginRead();
    975   ASSERT_THAT(ReadPacket(), IsEmpty());
    976 }
    977 
    978 TEST_F(TraceBufferTest, Malicious_DeclareMorePacketsBeyondBoundaries) {
    979   ResetBuffer(4096);
    980   SuppressSanityDchecksForTesting();
    981   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
    982       .AddPacket(64, 'a')
    983       .IncrementNumPackets()
    984       .IncrementNumPackets()
    985       .CopyIntoTraceBuffer();
    986   CreateChunk(ProducerID(1), WriterID(2), ChunkID(0))
    987       .IncrementNumPackets()
    988       .CopyIntoTraceBuffer();
    989   CreateChunk(ProducerID(1), WriterID(3), ChunkID(0))
    990       .AddPacket(32, 'b')
    991       .CopyIntoTraceBuffer();
    992   trace_buffer()->BeginRead();
    993   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(64, 'a')));
    994   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'b')));
    995   ASSERT_THAT(ReadPacket(), IsEmpty());
    996   ASSERT_THAT(ReadPacket(), IsEmpty());
    997 }
    998 
    999 TEST_F(TraceBufferTest, Malicious_ZeroVarintHeader) {
   1000   ResetBuffer(4096);
   1001   SuppressSanityDchecksForTesting();
   1002   // Create a standalone chunk where the varint header is == 0.
   1003   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1004       .AddPacket(4, 'a')
   1005       .ClearBytes(0, 1)
   1006       .AddPacket(4, 'b')
   1007       .CopyIntoTraceBuffer();
   1008   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
   1009       .AddPacket(4, 'c')
   1010       .CopyIntoTraceBuffer();
   1011   trace_buffer()->BeginRead();
   1012   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'c')));
   1013   ASSERT_THAT(ReadPacket(), IsEmpty());
   1014 }
   1015 
   1016 // Forge a chunk where the first packet is valid but the second packet has a
   1017 // varint header that continues beyond the end of the chunk (and also beyond the
   1018 // end of the buffer).
   1019 TEST_F(TraceBufferTest, Malicious_OverflowingVarintHeader) {
   1020   ResetBuffer(4096);
   1021   SuppressSanityDchecksForTesting();
   1022   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1023       .AddPacket(4079, 'a')  // 4079 := 4096 - sizeof(ChunkRecord) - 1
   1024       .AddPacket({0x82})  // 0x8*: that the varint continues on the next byte.
   1025       .CopyIntoTraceBuffer();
   1026   trace_buffer()->BeginRead();
   1027   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4079, 'a')));
   1028   ASSERT_THAT(ReadPacket(), IsEmpty());
   1029   ASSERT_THAT(ReadPacket(), IsEmpty());
   1030 }
   1031 
   1032 TEST_F(TraceBufferTest, Malicious_VarintHeaderTooBig) {
   1033   ResetBuffer(4096);
   1034   SuppressSanityDchecksForTesting();
   1035 
   1036   // Add a valid chunk.
   1037   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1038       .AddPacket(32, 'a')
   1039       .CopyIntoTraceBuffer();
   1040 
   1041   // Forge a packet which has a varint header that is just off by one.
   1042   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
   1043       .AddPacket({0x16, '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
   1044                   'c', 'd', 'e', 'f'})
   1045       .CopyIntoTraceBuffer();
   1046 
   1047   // Forge a packet which has a varint header that tries to hit an overflow.
   1048   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
   1049       .AddPacket({0xff, 0xff, 0xff, 0x7f})
   1050       .CopyIntoTraceBuffer();
   1051 
   1052   // Forge a packet which has a jumbo varint header: 0xff, 0xff .. 0x7f.
   1053   std::vector<uint8_t> chunk;
   1054   chunk.insert(chunk.end(), 128 - sizeof(ChunkRecord), 0xff);
   1055   chunk.back() = 0x7f;
   1056   trace_buffer()->CopyChunkUntrusted(
   1057       ProducerID(4), uid_t(0), WriterID(1), ChunkID(1), 1 /* num packets */,
   1058       0 /* flags*/, true /* chunk_complete */, chunk.data(), chunk.size());
   1059 
   1060   // Add a valid chunk.
   1061   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1062       .AddPacket(32, 'b')
   1063       .CopyIntoTraceBuffer();
   1064 
   1065   trace_buffer()->BeginRead();
   1066   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'a')));
   1067   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'b')));
   1068   ASSERT_THAT(ReadPacket(), IsEmpty());
   1069 }
   1070 
   1071 // Similar to Malicious_VarintHeaderTooBig, but this time the full chunk
   1072 // contains an enormous varint number that tries to overflow.
   1073 TEST_F(TraceBufferTest, Malicious_JumboVarint) {
   1074   ResetBuffer(64 * 1024);
   1075   SuppressSanityDchecksForTesting();
   1076 
   1077   std::vector<uint8_t> chunk;
   1078   chunk.insert(chunk.end(), 64 * 1024 - sizeof(ChunkRecord) * 2, 0xff);
   1079   chunk.back() = 0x7f;
   1080   for (int i = 0; i < 3; i++) {
   1081     trace_buffer()->CopyChunkUntrusted(
   1082         ProducerID(1), uid_t(0), WriterID(1), ChunkID(1), 1 /* num packets */,
   1083         0 /* flags */, true /* chunk_complete */, chunk.data(), chunk.size());
   1084   }
   1085 
   1086   trace_buffer()->BeginRead();
   1087   ASSERT_THAT(ReadPacket(), IsEmpty());
   1088 }
   1089 
   1090 // Like the Malicious_ZeroVarintHeader, but put the chunk in the middle of a
   1091 // sequence that would be otherwise valid. The zero-sized fragment should be
   1092 // skipped.
   1093 TEST_F(TraceBufferTest, Malicious_ZeroVarintHeaderInSequence) {
   1094   ResetBuffer(4096);
   1095   SuppressSanityDchecksForTesting();
   1096   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1097       .AddPacket(4, 'a', kContOnNextChunk)
   1098       .CopyIntoTraceBuffer();
   1099   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1100       .AddPacket(4, 'b', kContFromPrevChunk | kContOnNextChunk)
   1101       .ClearBytes(0, 1)
   1102       .CopyIntoTraceBuffer();
   1103   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
   1104       .AddPacket(4, 'c', kContFromPrevChunk)
   1105       .AddPacket(4, 'd')
   1106       .CopyIntoTraceBuffer();
   1107   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
   1108       .AddPacket(4, 'e')
   1109       .CopyIntoTraceBuffer();
   1110   CreateChunk(ProducerID(2), WriterID(1), ChunkID(3))
   1111       .AddPacket(5, 'f')
   1112       .CopyIntoTraceBuffer();
   1113 
   1114   trace_buffer()->BeginRead();
   1115   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'a'),
   1116                                         FakePacketFragment(4, 'c')));
   1117   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'd')));
   1118   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'e')));
   1119   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(5, 'f')));
   1120   ASSERT_THAT(ReadPacket(), IsEmpty());
   1121 }
   1122 
   1123 // Similar to Malicious_ZeroVarintHeaderInSequence, but this time the zero-sized
   1124 // fragment is the last fragment for a chunk and is marked for continuation. The
   1125 // zero-sized fragment should be skipped.
   1126 TEST_F(TraceBufferTest, Malicious_ZeroVarintHeaderAtEndOfChunk) {
   1127   ResetBuffer(4096);
   1128   SuppressSanityDchecksForTesting();
   1129   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1130       .AddPacket(4, 'a')
   1131       .AddPacket(4, 'b', kContOnNextChunk)
   1132       .ClearBytes(4, 4)
   1133       .CopyIntoTraceBuffer();
   1134   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1135       .AddPacket(4, 'c', kContFromPrevChunk)
   1136       .AddPacket(4, 'd')
   1137       .CopyIntoTraceBuffer();
   1138   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
   1139       .AddPacket(4, 'e')
   1140       .CopyIntoTraceBuffer();
   1141   CreateChunk(ProducerID(2), WriterID(1), ChunkID(3))
   1142       .AddPacket(4, 'f')
   1143       .CopyIntoTraceBuffer();
   1144 
   1145   trace_buffer()->BeginRead();
   1146   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'a')));
   1147   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'c')));
   1148   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'd')));
   1149   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'e')));
   1150   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'f')));
   1151   ASSERT_THAT(ReadPacket(), IsEmpty());
   1152 }
   1153 
   1154 TEST_F(TraceBufferTest, Malicious_PatchOutOfBounds) {
   1155   ResetBuffer(4096);
   1156   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1157       .AddPacket(2048, 'a')
   1158       .CopyIntoTraceBuffer();
   1159   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1160       .AddPacket(16, 'b')
   1161       .CopyIntoTraceBuffer();
   1162   size_t offsets[] = {13,          16,          size_t(-4),
   1163                       size_t(-8),  size_t(-12), size_t(-16),
   1164                       size_t(-20), size_t(-32), size_t(-1024)};
   1165   for (size_t offset : offsets) {
   1166     ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(1), ChunkID(1),
   1167                                        {{offset, {{'0', 'd', 'a', 'y'}}}}));
   1168   }
   1169 }
   1170 
   1171 TEST_F(TraceBufferTest, Malicious_OverrideWithShorterChunkSize) {
   1172   ResetBuffer(4096);
   1173   SuppressSanityDchecksForTesting();
   1174   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1175       .AddPacket(2048, 'a')
   1176       .CopyIntoTraceBuffer();
   1177   // The service should ignore this override of the chunk since the chunk size
   1178   // is different.
   1179   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1180       .AddPacket(1024, 'b')
   1181       .CopyIntoTraceBuffer();
   1182   trace_buffer()->BeginRead();
   1183   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048, 'a')));
   1184   ASSERT_THAT(ReadPacket(), IsEmpty());
   1185 }
   1186 
   1187 TEST_F(TraceBufferTest, Malicious_OverrideWithShorterChunkSizeAfterRead) {
   1188   ResetBuffer(4096);
   1189   SuppressSanityDchecksForTesting();
   1190 
   1191   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1192       .AddPacket(30, 'a')
   1193       .AddPacket(40, 'b')
   1194       .CopyIntoTraceBuffer();
   1195   trace_buffer()->BeginRead();
   1196   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'a')));
   1197   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'b')));
   1198 
   1199   // The service should ignore this override of the chunk since the chunk size
   1200   // is different.
   1201   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1202       .AddPacket(10, 'a')
   1203       .AddPacket(10, 'b')
   1204       .AddPacket(10, 'c')
   1205       .CopyIntoTraceBuffer();
   1206   trace_buffer()->BeginRead();
   1207   ASSERT_THAT(ReadPacket(), IsEmpty());
   1208 
   1209   // Test that the service didn't get stuck in some indeterminate state.
   1210   // Writing a valid chunk with a larger ID should make things work again.
   1211   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1212       .AddPacket(10, 'd')
   1213       .AddPacket(10, 'e')
   1214       .CopyIntoTraceBuffer();
   1215   trace_buffer()->BeginRead();
   1216   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
   1217   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'e')));
   1218   ASSERT_THAT(ReadPacket(), IsEmpty());
   1219 }
   1220 
   1221 TEST_F(TraceBufferTest, Malicious_OverrideWithDifferentOffsetAfterRead) {
   1222   ResetBuffer(4096);
   1223   SuppressSanityDchecksForTesting();
   1224 
   1225   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1226       .AddPacket(30, 'a')
   1227       .AddPacket(40, 'b')
   1228       .PadTo(512)
   1229       .CopyIntoTraceBuffer();
   1230   trace_buffer()->BeginRead();
   1231   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'a')));
   1232   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'b')));
   1233 
   1234   // The attacker in this case speculates on the fact that the read pointer is
   1235   // @ 70 which is >> the size of the new chunk we overwrite.
   1236   // The service will not discard this override since the chunk size is correct.
   1237   // However, it should detect that the packet headers at the current read
   1238   // offset are invalid and skip the read of this chunk.
   1239   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1240       .AddPacket(10, 'a')
   1241       .AddPacket(10, 'b')
   1242       .AddPacket(10, 'c')
   1243       .PadTo(512)
   1244       .CopyIntoTraceBuffer();
   1245   trace_buffer()->BeginRead();
   1246   ASSERT_THAT(ReadPacket(), IsEmpty());
   1247 
   1248   // Test that the service didn't get stuck in some indeterminate state.
   1249   // Writing a valid chunk with a larger ID should make things work again.
   1250   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1251       .AddPacket(10, 'd')
   1252       .AddPacket(10, 'e')
   1253       .PadTo(512)
   1254       .CopyIntoTraceBuffer();
   1255   trace_buffer()->BeginRead();
   1256   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
   1257   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'e')));
   1258   ASSERT_THAT(ReadPacket(), IsEmpty());
   1259 }
   1260 
   1261 // -------------------
   1262 // SequenceIterator tests
   1263 // -------------------
   1264 TEST_F(TraceBufferTest, Iterator_OneStreamOrdered) {
   1265   ResetBuffer(64 * 1024);
   1266   AppendChunks({
   1267       {ProducerID(1), WriterID(1), ChunkID(0)},
   1268       {ProducerID(1), WriterID(1), ChunkID(1)},
   1269       {ProducerID(1), WriterID(1), ChunkID(2)},
   1270       {ProducerID(1), WriterID(1), ChunkID(5)},
   1271       {ProducerID(1), WriterID(1), ChunkID(6)},
   1272       {ProducerID(1), WriterID(1), ChunkID(7)},
   1273   });
   1274   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {}));
   1275   ASSERT_TRUE(IteratorSeqEq(ProducerID(-1), WriterID(-1), {}));
   1276   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(1), {0, 1, 2}));
   1277 }
   1278 
   1279 TEST_F(TraceBufferTest, Iterator_OneStreamWrapping) {
   1280   ResetBuffer(64 * 1024);
   1281   AppendChunks({
   1282       {ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 2)},
   1283       {ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 1)},
   1284       {ProducerID(1), WriterID(1), ChunkID(kMaxChunkID)},
   1285       {ProducerID(1), WriterID(1), ChunkID(0)},
   1286       {ProducerID(1), WriterID(1), ChunkID(1)},
   1287       {ProducerID(1), WriterID(1), ChunkID(2)},
   1288   });
   1289   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {}));
   1290   ASSERT_TRUE(IteratorSeqEq(ProducerID(-1), WriterID(-1), {}));
   1291   ASSERT_TRUE(
   1292       IteratorSeqEq(ProducerID(1), WriterID(1),
   1293                     {kMaxChunkID - 2, kMaxChunkID - 1, kMaxChunkID, 0, 1, 2}));
   1294 }
   1295 
   1296 TEST_F(TraceBufferTest, Iterator_ManyStreamsOrdered) {
   1297   ResetBuffer(64 * 1024);
   1298   AppendChunks({
   1299       {ProducerID(1), WriterID(1), ChunkID(0)},
   1300       {ProducerID(1), WriterID(1), ChunkID(1)},
   1301       {ProducerID(1), WriterID(2), ChunkID(0)},
   1302       {ProducerID(3), WriterID(1), ChunkID(0)},
   1303       {ProducerID(1), WriterID(2), ChunkID(1)},
   1304       {ProducerID(1), WriterID(2), ChunkID(2)},
   1305       {ProducerID(3), WriterID(1), ChunkID(1)},
   1306       {ProducerID(1), WriterID(1), ChunkID(2)},
   1307       {ProducerID(3), WriterID(1), ChunkID(2)},
   1308   });
   1309   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(1), {0, 1, 2}));
   1310   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {0, 1, 2}));
   1311   ASSERT_TRUE(IteratorSeqEq(ProducerID(3), WriterID(1), {0, 1, 2}));
   1312 }
   1313 
   1314 TEST_F(TraceBufferTest, Iterator_ManyStreamsWrapping) {
   1315   ResetBuffer(64 * 1024);
   1316   auto Neg = [](int x) -> ChunkID {
   1317     return kMaxChunkID + static_cast<ChunkID>(x) + 1;
   1318   };
   1319   AppendChunks({
   1320       {ProducerID(1), WriterID(1), ChunkID(Neg(-2))},
   1321       {ProducerID(1), WriterID(1), ChunkID(Neg(-1))},
   1322       {ProducerID(1), WriterID(2), ChunkID(Neg(-1))},
   1323       {ProducerID(3), WriterID(1), ChunkID(Neg(-1))},
   1324       {ProducerID(1), WriterID(2), ChunkID(0)},
   1325       {ProducerID(1), WriterID(2), ChunkID(1)},
   1326       {ProducerID(3), WriterID(1), ChunkID(0)},
   1327       {ProducerID(1), WriterID(1), ChunkID(0)},
   1328       {ProducerID(3), WriterID(1), ChunkID(1)},
   1329   });
   1330   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(1), {Neg(-2), Neg(-1), 0}));
   1331   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {Neg(-1), 0, 1}));
   1332   ASSERT_TRUE(IteratorSeqEq(ProducerID(3), WriterID(1), {Neg(-1), 0, 1}));
   1333 }
   1334 
   1335 // -------------------
   1336 // Re-writing same chunk id
   1337 // -------------------
   1338 
   1339 TEST_F(TraceBufferTest, Override_ReCommitBeforeRead) {
   1340   ResetBuffer(4096);
   1341   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1342       .AddPacket(100, 'a')
   1343       .AddPacket(100, 'b')
   1344       .PadTo(512)
   1345       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
   1346   EXPECT_EQ(0u, trace_buffer()->stats().chunks_rewritten());
   1347   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1348       .AddPacket(100, 'a')
   1349       .AddPacket(100, 'b')
   1350       .AddPacket(100, 'c')
   1351       .AddPacket(100, 'd')
   1352       .PadTo(512)
   1353       .CopyIntoTraceBuffer();
   1354   trace_buffer()->BeginRead();
   1355   EXPECT_EQ(1u, trace_buffer()->stats().chunks_rewritten());
   1356   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'a')));
   1357   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'b')));
   1358   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'c')));
   1359   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'd')));
   1360   ASSERT_THAT(ReadPacket(), IsEmpty());
   1361 }
   1362 
   1363 TEST_F(TraceBufferTest, Override_ReCommitAfterPartialRead) {
   1364   ResetBuffer(4096);
   1365   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1366       .AddPacket(20, 'a')
   1367       .AddPacket(30, 'b')
   1368       .PadTo(512)
   1369       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
   1370   trace_buffer()->BeginRead();
   1371   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1372 
   1373   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1374       .AddPacket(20, 'a')
   1375       .AddPacket(30, 'b')
   1376       .AddPacket(40, 'c')
   1377       .AddPacket(50, 'd')
   1378       .PadTo(512)
   1379       .CopyIntoTraceBuffer();
   1380   trace_buffer()->BeginRead();
   1381   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1382   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1383   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1384   ASSERT_THAT(ReadPacket(), IsEmpty());
   1385 }
   1386 
   1387 TEST_F(TraceBufferTest, Override_ReCommitAfterFullRead) {
   1388   ResetBuffer(4096);
   1389   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1390       .AddPacket(20, 'a')
   1391       .AddPacket(30, 'b')
   1392       .PadTo(512)
   1393       .CopyIntoTraceBuffer();
   1394   trace_buffer()->BeginRead();
   1395   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1396   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1397 
   1398   // Overriding a complete packet here would trigger a DCHECK because the packet
   1399   // was already marked as complete.
   1400   SuppressSanityDchecksForTesting();
   1401   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1402       .AddPacket(20, 'a')
   1403       .AddPacket(30, 'b')
   1404       .AddPacket(40, 'c')
   1405       .AddPacket(50, 'd')
   1406       .PadTo(512)
   1407       .CopyIntoTraceBuffer();
   1408   trace_buffer()->BeginRead();
   1409   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1410   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1411   ASSERT_THAT(ReadPacket(), IsEmpty());
   1412 }
   1413 
   1414 // See also the Malicious_Override* tests above.
   1415 TEST_F(TraceBufferTest, Override_ReCommitInvalid) {
   1416   ResetBuffer(4096);
   1417   SuppressSanityDchecksForTesting();
   1418   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1419       .AddPacket(20, 'a')
   1420       .AddPacket(30, 'b')
   1421       .PadTo(512)
   1422       .CopyIntoTraceBuffer();
   1423   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1424       .AddPacket(40, 'c')
   1425       .AddPacket(50, 'd')
   1426       .PadTo(512)
   1427       .CopyIntoTraceBuffer();
   1428   trace_buffer()->BeginRead();
   1429   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1430   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1431   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1432 
   1433   // This should not happen when the producer behaves correctly, since it
   1434   // shouldn't change the contents of chunk 0 after having allocated chunk 1.
   1435   //
   1436   // Since we've already started reading from chunk 1, TraceBuffer will
   1437   // recognize this and discard the override.
   1438   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1439       .AddPacket(20, 'e')
   1440       .AddPacket(60, 'f')
   1441       .AddPacket(70, 'g')
   1442       .PadTo(512)
   1443       .CopyIntoTraceBuffer();
   1444   trace_buffer()->BeginRead();
   1445   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1446   ASSERT_THAT(ReadPacket(), IsEmpty());
   1447 }
   1448 
   1449 TEST_F(TraceBufferTest, Override_ReCommitReordered) {
   1450   ResetBuffer(4096);
   1451   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1452       .AddPacket(20, 'a')
   1453       .AddPacket(30, 'b')
   1454       .PadTo(512)
   1455       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
   1456 
   1457   trace_buffer()->BeginRead();
   1458   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1459 
   1460   // Recommit chunk 0 and add chunk 1, but do this out of order.
   1461   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1462       .AddPacket(50, 'd')
   1463       .AddPacket(60, 'e')
   1464       .PadTo(512)
   1465       .CopyIntoTraceBuffer();
   1466   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1467       .AddPacket(20, 'a')
   1468       .AddPacket(30, 'b')
   1469       .AddPacket(40, 'c')
   1470       .PadTo(512)
   1471       .CopyIntoTraceBuffer();
   1472 
   1473   trace_buffer()->BeginRead();
   1474   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1475   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1476   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1477   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(60, 'e')));
   1478 }
   1479 
   1480 TEST_F(TraceBufferTest, Override_ReCommitReorderedFragmenting) {
   1481   ResetBuffer(4096);
   1482   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1483       .AddPacket(20, 'a')
   1484       .AddPacket(30, 'b')
   1485       .PadTo(512)
   1486       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
   1487 
   1488   trace_buffer()->BeginRead();
   1489   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1490 
   1491   // Recommit chunk 0 and add chunk 1, but do this out of order.
   1492   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1493       .AddPacket(50, 'd', kContFromPrevChunk)
   1494       .AddPacket(60, 'e')
   1495       .PadTo(512)
   1496       .CopyIntoTraceBuffer();
   1497   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1498       .AddPacket(20, 'a')
   1499       .AddPacket(30, 'b')
   1500       .AddPacket(40, 'c', kContOnNextChunk)
   1501       .PadTo(512)
   1502       .CopyIntoTraceBuffer();
   1503 
   1504   trace_buffer()->BeginRead();
   1505   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1506   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c'),
   1507                                         FakePacketFragment(50, 'd')));
   1508   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(60, 'e')));
   1509 }
   1510 
   1511 TEST_F(TraceBufferTest, Override_ReCommitSameBeforeRead) {
   1512   ResetBuffer(4096);
   1513   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1514       .AddPacket(20, 'a')
   1515       .AddPacket(30, 'b')
   1516       .PadTo(512)
   1517       .CopyIntoTraceBuffer();
   1518 
   1519   // Commit again the same chunk.
   1520   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1521       .AddPacket(20, 'a')
   1522       .AddPacket(30, 'b')
   1523       .PadTo(512)
   1524       .CopyIntoTraceBuffer();
   1525 
   1526   // Then write some new content in a new chunk.
   1527   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1528       .AddPacket(40, 'c')
   1529       .AddPacket(50, 'd')
   1530       .PadTo(512)
   1531       .CopyIntoTraceBuffer();
   1532 
   1533   // The reader should keep reading from the new chunk.
   1534   trace_buffer()->BeginRead();
   1535   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1536   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1537   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1538   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1539   ASSERT_THAT(ReadPacket(), IsEmpty());
   1540 }
   1541 
   1542 TEST_F(TraceBufferTest, Override_ReCommitSameAfterRead) {
   1543   ResetBuffer(4096);
   1544   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1545       .AddPacket(20, 'a')
   1546       .AddPacket(30, 'b')
   1547       .PadTo(512)
   1548       .CopyIntoTraceBuffer();
   1549   trace_buffer()->BeginRead();
   1550   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1551   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1552 
   1553   // This re-commit should be ignored. We just re-committed an identical chunk.
   1554   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1555       .AddPacket(20, 'a')
   1556       .AddPacket(30, 'b')
   1557       .PadTo(512)
   1558       .CopyIntoTraceBuffer();
   1559 
   1560   // Then write some new content in a new chunk.
   1561   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1562       .AddPacket(40, 'c')
   1563       .AddPacket(50, 'd')
   1564       .PadTo(512)
   1565       .CopyIntoTraceBuffer();
   1566 
   1567   // The reader should keep reading from the new chunk.
   1568   trace_buffer()->BeginRead();
   1569   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1570   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1571   ASSERT_THAT(ReadPacket(), IsEmpty());
   1572 }
   1573 
   1574 TEST_F(TraceBufferTest, Override_ReCommitIncompleteAfterReadOutOfOrder) {
   1575   ResetBuffer(4096);
   1576   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1577       .AddPacket(20, 'a')
   1578       .AddPacket(30, 'b')
   1579       .PadTo(512)
   1580       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
   1581   trace_buffer()->BeginRead();
   1582   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1583   // The last packet in an incomplete chunk should be ignored as the producer
   1584   // may not have completed writing it.
   1585   ASSERT_THAT(ReadPacket(), IsEmpty());
   1586 
   1587   // Then write some new content in a new chunk.
   1588   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1589       .AddPacket(40, 'c')
   1590       .AddPacket(50, 'd')
   1591       .PadTo(512)
   1592       .CopyIntoTraceBuffer();
   1593   // The read still shouldn't be advancing past the incomplete chunk.
   1594   trace_buffer()->BeginRead();
   1595   ASSERT_THAT(ReadPacket(), IsEmpty());
   1596 
   1597   // Recommit the original chunk with no changes but mark as complete.
   1598   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1599       .AddPacket(20, 'a')
   1600       .AddPacket(30, 'b')
   1601       .PadTo(512)
   1602       .CopyIntoTraceBuffer(/*chunk_complete=*/true);
   1603 
   1604   // Reading should resume from the now completed chunk.
   1605   trace_buffer()->BeginRead();
   1606   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
   1607   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
   1608   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1609   ASSERT_THAT(ReadPacket(), IsEmpty());
   1610 }
   1611 
   1612 TEST_F(TraceBufferTest, Override_ReCommitIncompleteFragmenting) {
   1613   ResetBuffer(4096);
   1614   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1615       .AddPacket(20, 'a')
   1616       .AddPacket(30, 'b', kContOnNextChunk)
   1617       .PadTo(512)
   1618       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
   1619   trace_buffer()->BeginRead();
   1620   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
   1621   // The last packet in an incomplete chunk should be ignored as the producer
   1622   // may not have completed writing it.
   1623   ASSERT_THAT(ReadPacket(), IsEmpty());
   1624 
   1625   // Then write some new content in a new chunk.
   1626   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1627       .AddPacket(40, 'c', kContFromPrevChunk)
   1628       .AddPacket(50, 'd')
   1629       .PadTo(512)
   1630       .CopyIntoTraceBuffer();
   1631   // The read still shouldn't be advancing past the incomplete chunk.
   1632   trace_buffer()->BeginRead();
   1633   ASSERT_THAT(ReadPacket(), IsEmpty());
   1634 
   1635   // Recommit the original chunk with no changes but mark as complete.
   1636   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1637       .AddPacket(20, 'a')
   1638       .AddPacket(30, 'b', kContOnNextChunk)
   1639       .PadTo(512)
   1640       .CopyIntoTraceBuffer(/*chunk_complete=*/true);
   1641 
   1642   // Reading should resume from the now completed chunk.
   1643   trace_buffer()->BeginRead();
   1644   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b'),
   1645                                         FakePacketFragment(40, 'c')));
   1646   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
   1647   ASSERT_THAT(ReadPacket(), IsEmpty());
   1648 }
   1649 
   1650 TEST_F(TraceBufferTest, DiscardPolicy) {
   1651   ResetBuffer(4096, TraceBuffer::kDiscard);
   1652 
   1653   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1654       .AddPacket(96 - 16, 'a')
   1655       .CopyIntoTraceBuffer();
   1656   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1657       .AddPacket(4000 - 16, 'b')
   1658       .CopyIntoTraceBuffer();
   1659 
   1660   trace_buffer()->BeginRead();
   1661   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(96 - 16, 'a')));
   1662 
   1663   // As long as the reader catches up, writes should succeed.
   1664   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
   1665       .AddPacket(48 - 16, 'c')
   1666       .CopyIntoTraceBuffer();
   1667   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
   1668       .AddPacket(48 - 16, 'd')
   1669       .CopyIntoTraceBuffer();
   1670 
   1671   trace_buffer()->BeginRead();
   1672   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4000 - 16, 'b')));
   1673   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(48 - 16, 'c')));
   1674   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(48 - 16, 'd')));
   1675   ASSERT_THAT(ReadPacket(), IsEmpty());
   1676 
   1677   // This will succeed.
   1678   CreateChunk(ProducerID(1), WriterID(1), ChunkID(4))
   1679       .AddPacket(4000 - 16, 'e')
   1680       .CopyIntoTraceBuffer();
   1681 
   1682   // But this will fail, preventing any further write.
   1683   for (int i = 0; i < 3; i++) {
   1684     CreateChunk(ProducerID(1), WriterID(i + 2), ChunkID(0))
   1685         .AddPacket(120 - 16, 'X')
   1686         .CopyIntoTraceBuffer();
   1687   }
   1688 
   1689   trace_buffer()->BeginRead();
   1690   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4000 - 16, 'e')));
   1691   ASSERT_THAT(ReadPacket(), IsEmpty());
   1692 
   1693   // Even after the reader catches up, writes should still be discarded.
   1694   for (int i = 0; i < 3; i++) {
   1695     CreateChunk(ProducerID(1), WriterID(i + 10), ChunkID(0))
   1696         .AddPacket(64 - 16, 'X')
   1697         .CopyIntoTraceBuffer();
   1698   }
   1699   trace_buffer()->BeginRead();
   1700   ASSERT_THAT(ReadPacket(), IsEmpty());
   1701 }
   1702 
   1703 TEST_F(TraceBufferTest, MissingPacketsOnSequence) {
   1704   ResetBuffer(4096);
   1705   SuppressSanityDchecksForTesting();
   1706   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
   1707       .AddPacket(10, 'a')
   1708       .AddPacket(10, 'b')
   1709       .AddPacket(10, 'c', kContOnNextChunk)
   1710       .CopyIntoTraceBuffer();
   1711   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
   1712       .AddPacket(10, 'u')
   1713       .AddPacket(10, 'v')
   1714       .AddPacket(10, 'w')
   1715       .ClearBytes(10, 1)  // Clears the varint header of packet "v".
   1716       .CopyIntoTraceBuffer();
   1717 
   1718   bool previous_packet_dropped = false;
   1719 
   1720   trace_buffer()->BeginRead();
   1721   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1722               ElementsAre(FakePacketFragment(10, 'a')));
   1723   // First packet in first sequence, so previous one didn't exist.
   1724   ASSERT_TRUE(previous_packet_dropped);
   1725 
   1726   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1727               ElementsAre(FakePacketFragment(10, 'b')));
   1728   // We read packet "a" before.
   1729   ASSERT_FALSE(previous_packet_dropped);
   1730 
   1731   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1732               ElementsAre(FakePacketFragment(10, 'u')));
   1733   // First packet in second sequence, so previous one didn't exist.
   1734   ASSERT_TRUE(previous_packet_dropped);
   1735 
   1736   // Packet "v" in second sequence is corrupted, so chunk will be skipped.
   1737   ASSERT_THAT(ReadPacket(), IsEmpty());
   1738 
   1739   CreateChunk(ProducerID(2), WriterID(1), ChunkID(1))
   1740       .AddPacket(10, 'x')
   1741       .AddPacket(10, 'y')
   1742       .CopyIntoTraceBuffer();
   1743   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
   1744       .AddPacket(10, 'd', kContFromPrevChunk)
   1745       .AddPacket(10, 'e')
   1746       .CopyIntoTraceBuffer();
   1747 
   1748   trace_buffer()->BeginRead();
   1749   ASSERT_THAT(
   1750       ReadPacket(nullptr, &previous_packet_dropped),
   1751       ElementsAre(FakePacketFragment(10, 'c'), FakePacketFragment(10, 'd')));
   1752   // We read packet "b" before.
   1753   ASSERT_FALSE(previous_packet_dropped);
   1754 
   1755   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1756               ElementsAre(FakePacketFragment(10, 'e')));
   1757   // We read packet "d" before.
   1758   ASSERT_FALSE(previous_packet_dropped);
   1759 
   1760   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1761               ElementsAre(FakePacketFragment(10, 'x')));
   1762   // We didn't read packets "v" and "w".
   1763   ASSERT_TRUE(previous_packet_dropped);
   1764 
   1765   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1766               ElementsAre(FakePacketFragment(10, 'y')));
   1767   // We read packet "x".
   1768   ASSERT_FALSE(previous_packet_dropped);
   1769 
   1770   ASSERT_THAT(ReadPacket(), IsEmpty());
   1771 
   1772   // Write two large chunks that don't fit into the buffer at the same time. We
   1773   // will drop the former one before we can read it.
   1774   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
   1775       .AddPacket(2000, 'f')
   1776       .CopyIntoTraceBuffer();
   1777   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
   1778       .AddPacket(3000, 'g')
   1779       .CopyIntoTraceBuffer();
   1780 
   1781   trace_buffer()->BeginRead();
   1782   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1783               ElementsAre(FakePacketFragment(3000, 'g')));
   1784   // We didn't read packet "f".
   1785   ASSERT_TRUE(previous_packet_dropped);
   1786 
   1787   CreateChunk(ProducerID(2), WriterID(1), ChunkID(2))
   1788       .AddPacket(10, 'z')
   1789       .CopyIntoTraceBuffer();
   1790 
   1791   trace_buffer()->BeginRead();
   1792   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
   1793               ElementsAre(FakePacketFragment(10, 'z')));
   1794   // We've lost any state from the second producer's sequence because all its
   1795   // previous chunks were removed from the buffer due to the two large chunks.
   1796   // So the buffer can't be sure that no packets were dropped.
   1797   ASSERT_TRUE(previous_packet_dropped);
   1798 }
   1799 
   1800 // TODO(primiano): test stats().
   1801 // TODO(primiano): test multiple streams interleaved.
   1802 // TODO(primiano): more testing on packet merging.
   1803 
   1804 }  // namespace perfetto
   1805