Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2018 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 #ifndef SRC_TRACING_CORE_TRACE_BUFFER_H_
     18 #define SRC_TRACING_CORE_TRACE_BUFFER_H_
     19 
     20 #include <stdint.h>
     21 #include <string.h>
     22 
     23 #include <array>
     24 #include <limits>
     25 #include <map>
     26 #include <tuple>
     27 
     28 #include "perfetto/base/logging.h"
     29 #include "perfetto/base/paged_memory.h"
     30 #include "perfetto/base/thread_annotations.h"
     31 #include "perfetto/tracing/core/basic_types.h"
     32 #include "perfetto/tracing/core/slice.h"
     33 #include "perfetto/tracing/core/trace_stats.h"
     34 
     35 namespace perfetto {
     36 
     37 class TracePacket;
     38 
     39 // The main buffer, owned by the tracing service, where all the trace data is
     40 // ultimately stored into. The service will own several instances of this class,
     41 // at least one per active consumer (as defined in the |buffers| section of
     42 // trace_config.proto) and will copy chunks from the producer's shared memory
     43 // buffers into here when a CommitData IPC is received.
     44 //
     45 // Writing into the buffer
     46 // -----------------------
     47 // Data is copied from the SMB(s) using CopyChunkUntrusted(). The buffer will
     48 // hence contain data coming from different producers and different writer
     49 // sequences, more specifically:
     50 // - The service receives data by several producer(s), identified by their ID.
     51 // - Each producer writes several sequences identified by the same WriterID.
     52 //   (they correspond to TraceWriter instances in the producer).
     53 // - Each Writer writes, in order, several chunks.
     54 // - Each chunk contains zero, one, or more TracePacket(s), or even just
     55 //   fragments of packets (when they span across several chunks).
     56 //
     57 // So at any point in time, the buffer will contain a variable number of logical
     58 // sequences identified by the {ProducerID, WriterID} tuple. Any given chunk
     59 // will only contain packets (or fragments) belonging to the same sequence.
     60 //
     61 // The buffer operates by default as a ring buffer.
     62 // It has two overwrite policies:
     63 //  1. kOverwrite (default): if the write pointer reaches the read pointer, old
     64 //     unread chunks will be overwritten by new chunks.
     65 //  2. kDiscard: if the write pointer reaches the read pointer, unread chunks
     66 //     are preserved and the new chunks are discarded. Any future write becomes
     67 //     a no-op, even if the reader manages to fully catch up. This is because
     68 //     once a chunk is discarded, the sequence of packets is broken and trying
     69 //     to recover would be too hard (also due to the fact that, at the same
     70 //     time, we allow out-of-order commits and chunk re-writes).
     71 //
     72 // Chunks are (over)written in the same order of the CopyChunkUntrusted() calls.
     73 // When overwriting old content, entire chunks are overwritten or clobbered.
     74 // The buffer never leaves a partial chunk around. Chunks' payload is copied
     75 // as-is, but their header is not and is repacked in order to keep the
     76 // ProducerID around.
     77 //
     78 // Chunks are stored in the buffer next to each other. Each chunk is prefixed by
     79 // an inline header (ChunkRecord), which contains most of the fields of the
     80 // SharedMemoryABI ChunkHeader + the ProducerID + the size of the payload.
     81 // It's a conventional binary object stream essentially, where each ChunkRecord
     82 // tells where it ends and hence where to find the next one, like this:
     83 //
     84 //          .-------------------------. 16 byte boundary
     85 //          | ChunkRecord:   16 bytes |
     86 //          | - chunk id:     4 bytes |
     87 //          | - producer id:  2 bytes |
     88 //          | - writer id:    2 bytes |
     89 //          | - #fragments:   2 bytes |
     90 //    +-----+ - record size:  2 bytes |
     91 //    |     | - flags+pad:    4 bytes |
     92 //    |     +-------------------------+
     93 //    |     |                         |
     94 //    |     :     Chunk payload       :
     95 //    |     |                         |
     96 //    |     +-------------------------+
     97 //    |     |    Optional padding     |
     98 //    +---> +-------------------------+ 16 byte boundary
     99 //          |      ChunkRecord        |
    100 //          :                         :
    101 // Chunks stored in the buffer are always rounded up to 16 bytes (that is
    102 // sizeof(ChunkRecord)), in order to avoid further inner fragmentation.
    103 // Special "padding" chunks can be put in the buffer, e.g. in the case when we
    104 // try to write a chunk of size N while the write pointer is at the end of the
    105 // buffer, but the write pointer is < N bytes from the end (and hence needs to
    106 // wrap over).
    107 // Because of this, the buffer is self-describing: the contents of the buffer
    108 // can be reconstructed by just looking at the buffer content (this will be
    109 // quite useful in future to recover the buffer from crash reports).
    110 //
    111 // However, in order to keep some operations (patching and reading) fast, a
    112 // lookaside index is maintained (in |index_|), keeping each chunk in the buffer
    113 // indexed by their {ProducerID, WriterID, ChunkID} tuple.
    114 //
    115 // Patching data out-of-band
    116 // -------------------------
    117 // This buffer also supports patching chunks' payload out-of-band, after they
    118 // have been stored. This is to allow producers to backfill the "size" fields
    119 // of the protos that spawn across several chunks, when the previous chunks are
    120 // returned to the service. The MaybePatchChunkContents() deals with the fact
    121 // that a chunk might have been lost (because of wrapping) by the time the OOB
    122 // IPC comes.
    123 //
    124 // Reading from the buffer
    125 // -----------------------
    126 // This class supports one reader only (the consumer). Reads are NOT idempotent
    127 // as they move the read cursors around. Reading back the buffer is the most
    128 // conceptually complex part. The ReadNextTracePacket() method operates with
    129 // whole packet granularity. Packets are returned only when all their fragments
    130 // are available.
    131 // This class takes care of:
    132 // - Gluing packets within the same sequence, even if they are not stored
    133 //   adjacently in the buffer.
    134 // - Re-ordering chunks within a sequence (using the ChunkID, which wraps).
    135 // - Detecting holes in packet fragments (because of loss of chunks).
    136 // Reads guarantee that packets for the same sequence are read in FIFO order
    137 // (according to their ChunkID), but don't give any guarantee about the read
    138 // order of packets from different sequences, see comments in
    139 // ReadNextTracePacket() below.
    140 class TraceBuffer {
    141  public:
    142   static const size_t InlineChunkHeaderSize;  // For test/fake_packet.{cc,h}.
    143 
    144   // See comment in the header above.
    145   enum OverwritePolicy { kOverwrite, kDiscard };
    146 
    147   // Argument for out-of-band patches applied through TryPatchChunkContents().
    148   struct Patch {
    149     // From SharedMemoryABI::kPacketHeaderSize.
    150     static constexpr size_t kSize = 4;
    151 
    152     size_t offset_untrusted;
    153     std::array<uint8_t, kSize> data;
    154   };
    155 
    156   // Identifiers that are constant for a packet sequence.
    157   struct PacketSequenceProperties {
    158     ProducerID producer_id_trusted;
    159     uid_t producer_uid_trusted;
    160     WriterID writer_id;
    161   };
    162 
    163   // Can return nullptr if the memory allocation fails.
    164   static std::unique_ptr<TraceBuffer> Create(size_t size_in_bytes,
    165                                              OverwritePolicy = kOverwrite);
    166 
    167   ~TraceBuffer();
    168 
    169   // Copies a Chunk from a producer Shared Memory Buffer into the trace buffer.
    170   // |src| points to the first packet in the SharedMemoryABI's chunk shared with
    171   // an untrusted producer. "untrusted" here means: the producer might be
    172   // malicious and might change |src| concurrently while we read it (internally
    173   // this method memcpy()-s first the chunk before processing it). None of the
    174   // arguments should be trusted, unless otherwise stated. We can trust that
    175   // |src| points to a valid memory area, but not its contents.
    176   //
    177   // This method may be called multiple times for the same chunk. In this case,
    178   // the original chunk's payload will be overridden and its number of fragments
    179   // and flags adjusted to match |num_fragments| and |chunk_flags|. The service
    180   // may use this to insert partial chunks (|chunk_complete = false|) before the
    181   // producer has committed them.
    182   //
    183   // If |chunk_complete| is |false|, the TraceBuffer will only consider the
    184   // first |num_fragments - 1| packets to be complete, since the producer may
    185   // not have finished writing the latest packet. Reading from a sequence will
    186   // also not progress past any incomplete chunks until they were rewritten with
    187   // |chunk_complete = true|, e.g. after a producer's commit.
    188   //
    189   // TODO(eseckler): Pass in a PacketStreamProperties instead of individual IDs.
    190   void CopyChunkUntrusted(ProducerID producer_id_trusted,
    191                           uid_t producer_uid_trusted,
    192                           WriterID writer_id,
    193                           ChunkID chunk_id,
    194                           uint16_t num_fragments,
    195                           uint8_t chunk_flags,
    196                           bool chunk_complete,
    197                           const uint8_t* src,
    198                           size_t size);
    199   // Applies a batch of |patches| to the given chunk, if the given chunk is
    200   // still in the buffer. Does nothing if the given ChunkID is gone.
    201   // Returns true if the chunk has been found and patched, false otherwise.
    202   // |other_patches_pending| is used to determine whether this is the only
    203   // batch of patches for the chunk or there is more.
    204   // If |other_patches_pending| == false, the chunk is marked as ready to be
    205   // consumed. If true, the state of the chunk is not altered.
    206   bool TryPatchChunkContents(ProducerID,
    207                              WriterID,
    208                              ChunkID,
    209                              const Patch* patches,
    210                              size_t patches_size,
    211                              bool other_patches_pending);
    212 
    213   // To read the contents of the buffer the caller needs to:
    214   //   BeginRead()
    215   //   while (ReadNextTracePacket(packet_fragments)) { ... }
    216   // No other calls to any other method should be interleaved between
    217   // BeginRead() and ReadNextTracePacket().
    218   // Reads in the TraceBuffer are NOT idempotent.
    219   void BeginRead();
    220 
    221   // Returns the next packet in the buffer, if any, and the producer_id,
    222   // producer_uid, and writer_id of the producer/writer that wrote it (as passed
    223   // in the CopyChunkUntrusted() call). Returns false if no packets can be read
    224   // at this point. If a packet was read successfully,
    225   // |previous_packet_on_sequence_dropped| is set to |true| if the previous
    226   // packet on the sequence was dropped from the buffer before it could be read
    227   // (e.g. because its chunk was overridden due to the ring buffer wrapping or
    228   // due to an ABI violation), and to |false| otherwise.
    229   //
    230   // This function returns only complete packets. Specifically:
    231   // When there is at least one complete packet in the buffer, this function
    232   // returns true and populates the TracePacket argument with the boundaries of
    233   // each fragment for one packet.
    234   // TracePacket will have at least one slice when this function returns true.
    235   // When there are no whole packets eligible to read (e.g. we are still missing
    236   // fragments) this function returns false.
    237   // This function guarantees also that packets for a given
    238   // {ProducerID, WriterID} are read in FIFO order.
    239   // This function does not guarantee any ordering w.r.t. packets belonging to
    240   // different WriterID(s). For instance, given the following packets copied
    241   // into the buffer:
    242   //   {ProducerID: 1, WriterID: 1}: P1 P2 P3
    243   //   {ProducerID: 1, WriterID: 2}: P4 P5 P6
    244   //   {ProducerID: 2, WriterID: 1}: P7 P8 P9
    245   // The following read sequence is possible:
    246   //   P1, P4, P7, P2, P3, P5, P8, P9, P6
    247   // But the following is guaranteed to NOT happen:
    248   //   P1, P5, P7, P4 (P4 cannot come after P5)
    249   bool ReadNextTracePacket(TracePacket*,
    250                            PacketSequenceProperties* sequence_properties,
    251                            bool* previous_packet_on_sequence_dropped);
    252 
    253   const TraceStats::BufferStats& stats() const { return stats_; }
    254   size_t size() const { return size_; }
    255 
    256  private:
    257   friend class TraceBufferTest;
    258 
    259   // ChunkRecord is a Chunk header stored inline in the |data_| buffer, before
    260   // the chunk payload (the packets' data). The |data_| buffer looks like this:
    261   // +---------------+------------------++---------------+-----------------+
    262   // | ChunkRecord 1 | Chunk payload 1  || ChunkRecord 2 | Chunk payload 2 | ...
    263   // +---------------+------------------++---------------+-----------------+
    264   // Most of the ChunkRecord fields are copied from SharedMemoryABI::ChunkHeader
    265   // (the chunk header used in the the shared memory buffers).
    266   // A ChunkRecord can be a special "padding" record. In this case its payload
    267   // should be ignored and the record should be just skipped.
    268   //
    269   // Full page move optimization:
    270   // This struct has to be exactly (sizeof(PageHeader) + sizeof(ChunkHeader))
    271   // (from shared_memory_abi.h) to allow full page move optimizations
    272   // (TODO(primiano): not implemented yet). In the special case of moving a full
    273   // 4k page that contains only one chunk, in fact, we can just ask the kernel
    274   // to move the full SHM page (see SPLICE_F_{GIFT,MOVE}) and overlay the
    275   // ChunkRecord on top of the moved SMB's header (page + chunk header).
    276   // This special requirement is covered by static_assert(s) in the .cc file.
    277   struct ChunkRecord {
    278     explicit ChunkRecord(size_t sz) : flags{0}, is_padding{0} {
    279       PERFETTO_DCHECK(sz >= sizeof(ChunkRecord) &&
    280                       sz % sizeof(ChunkRecord) == 0 && sz <= kMaxSize);
    281       size = static_cast<decltype(size)>(sz);
    282     }
    283 
    284     bool is_valid() const { return size != 0; }
    285 
    286     // Keep this structure packed and exactly 16 bytes (128 bits) big.
    287 
    288     // [32 bits] Monotonic counter within the same writer_id.
    289     ChunkID chunk_id = 0;
    290 
    291     // [16 bits] ID of the Producer from which the Chunk was copied from.
    292     ProducerID producer_id = 0;
    293 
    294     // [16 bits] Unique per Producer (but not within the service).
    295     // If writer_id == kWriterIdPadding the record should just be skipped.
    296     WriterID writer_id = 0;
    297 
    298     // Number of fragments contained in the chunk.
    299     uint16_t num_fragments = 0;
    300 
    301     // Size in bytes, including sizeof(ChunkRecord) itself.
    302     uint16_t size;
    303 
    304     uint8_t flags : 6;  // See SharedMemoryABI::ChunkHeader::flags.
    305     uint8_t is_padding : 1;
    306     uint8_t unused_flag : 1;
    307 
    308     // Not strictly needed, can be reused for more fields in the future. But
    309     // right now helps to spot chunks in hex dumps.
    310     char unused[3] = {'C', 'H', 'U'};
    311 
    312     static constexpr size_t kMaxSize =
    313         std::numeric_limits<decltype(size)>::max();
    314   };
    315 
    316   // Lookaside index entry. This serves two purposes:
    317   // 1) Allow a fast lookup of ChunkRecord by their ID (the tuple
    318   //   {ProducerID, WriterID, ChunkID}). This is used when applying out-of-band
    319   //   patches to the contents of the chunks after they have been copied into
    320   //   the TraceBuffer.
    321   // 2) keep the chunks ordered by their ID. This is used when reading back.
    322   // 3) Keep metadata about the status of the chunk, e.g. whether the contents
    323   //    have been read already and should be skipped in a future read pass.
    324   // This struct should not have any field that is essential for reconstructing
    325   // the contents of the buffer from a crash dump.
    326   struct ChunkMeta {
    327     // Key used for sorting in the map.
    328     struct Key {
    329       Key(ProducerID p, WriterID w, ChunkID c)
    330           : producer_id{p}, writer_id{w}, chunk_id{c} {}
    331 
    332       explicit Key(const ChunkRecord& cr)
    333           : Key(cr.producer_id, cr.writer_id, cr.chunk_id) {}
    334 
    335       // Note that this sorting doesn't keep into account the fact that ChunkID
    336       // will wrap over at some point. The extra logic in SequenceIterator deals
    337       // with that.
    338       bool operator<(const Key& other) const {
    339         return std::tie(producer_id, writer_id, chunk_id) <
    340                std::tie(other.producer_id, other.writer_id, other.chunk_id);
    341       }
    342 
    343       bool operator==(const Key& other) const {
    344         return std::tie(producer_id, writer_id, chunk_id) ==
    345                std::tie(other.producer_id, other.writer_id, other.chunk_id);
    346       }
    347 
    348       bool operator!=(const Key& other) const { return !(*this == other); }
    349 
    350       // These fields should match at all times the corresponding fields in
    351       // the |chunk_record|. They are copied here purely for efficiency to avoid
    352       // dereferencing the buffer all the time.
    353       ProducerID producer_id;
    354       WriterID writer_id;
    355       ChunkID chunk_id;
    356     };
    357 
    358     enum IndexFlags : uint8_t {
    359       // If set, the chunk state was kChunkComplete at the time it was copied.
    360       // If unset, the chunk was still kChunkBeingWritten while copied. When
    361       // reading from the chunk's sequence, the sequence will not advance past
    362       // this chunk until this flag is set.
    363       kComplete = 1 << 0,
    364 
    365       // If set, we skipped the last packet that we read from this chunk e.g.
    366       // because we it was a continuation from a previous chunk that was dropped
    367       // or due to an ABI violation.
    368       kLastReadPacketSkipped = 1 << 1
    369     };
    370 
    371     ChunkMeta(ChunkRecord* r, uint16_t p, bool complete, uint8_t f, uid_t u)
    372         : chunk_record{r}, trusted_uid{u}, flags{f}, num_fragments{p} {
    373       if (complete)
    374         index_flags = kComplete;
    375     }
    376 
    377     bool is_complete() const { return index_flags & kComplete; }
    378 
    379     void set_complete(bool complete) {
    380       if (complete) {
    381         index_flags |= kComplete;
    382       } else {
    383         index_flags &= ~kComplete;
    384       }
    385     }
    386 
    387     bool last_read_packet_skipped() const {
    388       return index_flags & kLastReadPacketSkipped;
    389     }
    390 
    391     void set_last_read_packet_skipped(bool skipped) {
    392       if (skipped) {
    393         index_flags |= kLastReadPacketSkipped;
    394       } else {
    395         index_flags &= ~kLastReadPacketSkipped;
    396       }
    397     }
    398 
    399     ChunkRecord* const chunk_record;  // Addr of ChunkRecord within |data_|.
    400     const uid_t trusted_uid;          // uid of the producer.
    401 
    402     // Flags set by TraceBuffer to track the state of the chunk in the index.
    403     uint8_t index_flags = 0;
    404 
    405     // Correspond to |chunk_record->flags| and |chunk_record->num_fragments|.
    406     // Copied here for performance reasons (avoids having to dereference
    407     // |chunk_record| while iterating over ChunkMeta) and to aid debugging in
    408     // case the buffer gets corrupted.
    409     uint8_t flags = 0;           // See SharedMemoryABI::ChunkHeader::flags.
    410     uint16_t num_fragments = 0;  // Total number of packet fragments.
    411 
    412     uint16_t num_fragments_read = 0;  // Number of fragments already read.
    413 
    414     // The start offset of the next fragment (the |num_fragments_read|-th) to be
    415     // read. This is the offset in bytes from the beginning of the ChunkRecord's
    416     // payload (the 1st fragment starts at |chunk_record| +
    417     // sizeof(ChunkRecord)).
    418     uint16_t cur_fragment_offset = 0;
    419   };
    420 
    421   using ChunkMap = std::map<ChunkMeta::Key, ChunkMeta>;
    422 
    423   // Allows to iterate over a sub-sequence of |index_| for all keys belonging to
    424   // the same {ProducerID,WriterID}. Furthermore takes into account the wrapping
    425   // of ChunkID. Instances are valid only as long as the |index_| is not altered
    426   // (can be used safely only between adjacent ReadNextTracePacket() calls).
    427   // The order of the iteration will proceed in the following order:
    428   // |wrapping_id| + 1 -> |seq_end|, |seq_begin| -> |wrapping_id|.
    429   // Practical example:
    430   // - Assume that kMaxChunkID == 7
    431   // - Assume that we have all 8 chunks in the range (0..7).
    432   // - Hence, |seq_begin| == c0, |seq_end| == c7
    433   // - Assume |wrapping_id| = 4 (c4 is the last chunk copied over
    434   //   through a CopyChunkUntrusted()).
    435   // The resulting iteration order will be: c5, c6, c7, c0, c1, c2, c3, c4.
    436   struct SequenceIterator {
    437     // Points to the 1st key (the one with the numerically min ChunkID).
    438     ChunkMap::iterator seq_begin;
    439 
    440     // Points one past the last key (the one with the numerically max ChunkID).
    441     ChunkMap::iterator seq_end;
    442 
    443     // Current iterator, always >= seq_begin && <= seq_end.
    444     ChunkMap::iterator cur;
    445 
    446     // The latest ChunkID written. Determines the start/end of the sequence.
    447     ChunkID wrapping_id;
    448 
    449     bool is_valid() const { return cur != seq_end; }
    450 
    451     ProducerID producer_id() const {
    452       PERFETTO_DCHECK(is_valid());
    453       return cur->first.producer_id;
    454     }
    455 
    456     WriterID writer_id() const {
    457       PERFETTO_DCHECK(is_valid());
    458       return cur->first.writer_id;
    459     }
    460 
    461     ChunkID chunk_id() const {
    462       PERFETTO_DCHECK(is_valid());
    463       return cur->first.chunk_id;
    464     }
    465 
    466     ChunkMeta& operator*() {
    467       PERFETTO_DCHECK(is_valid());
    468       return cur->second;
    469     }
    470 
    471     // Moves |cur| to the next chunk in the index.
    472     // is_valid() will become false after calling this, if this was the last
    473     // entry of the sequence.
    474     void MoveNext();
    475 
    476     void MoveToEnd() { cur = seq_end; }
    477   };
    478 
    479   enum class ReadAheadResult {
    480     kSucceededReturnSlices,
    481     kFailedMoveToNextSequence,
    482     kFailedStayOnSameSequence,
    483   };
    484 
    485   enum class ReadPacketResult {
    486     kSucceeded,
    487     kFailedInvalidPacket,
    488     kFailedEmptyPacket,
    489   };
    490 
    491   explicit TraceBuffer(OverwritePolicy);
    492   TraceBuffer(const TraceBuffer&) = delete;
    493   TraceBuffer& operator=(const TraceBuffer&) = delete;
    494 
    495   bool Initialize(size_t size);
    496 
    497   // Returns an object that allows to iterate over chunks in the |index_| that
    498   // have the same {ProducerID, WriterID} of
    499   // |seq_begin.first.{producer,writer}_id|. |seq_begin| must be an iterator to
    500   // the first entry in the |index_| that has a different {ProducerID, WriterID}
    501   // from the previous one. It is valid for |seq_begin| to be == index_.end()
    502   // (i.e. if the index is empty). The iteration takes care of ChunkID wrapping,
    503   // by using |last_chunk_id_|.
    504   SequenceIterator GetReadIterForSequence(ChunkMap::iterator seq_begin);
    505 
    506   // Used as a last resort when a buffer corruption is detected.
    507   void ClearContentsAndResetRWCursors();
    508 
    509   // Adds a padding record of the given size (must be a multiple of
    510   // sizeof(ChunkRecord)).
    511   void AddPaddingRecord(size_t);
    512 
    513   // Look for contiguous fragment of the same packet starting from |read_iter_|.
    514   // If a contiguous packet is found, all the fragments are pushed into
    515   // TracePacket and the function returns kSucceededReturnSlices. If not, the
    516   // function returns either kFailedMoveToNextSequence or
    517   // kFailedStayOnSameSequence, telling the caller to continue looking for
    518   // packets.
    519   ReadAheadResult ReadAhead(TracePacket*);
    520 
    521   // Deletes (by marking the record invalid and removing form the index) all
    522   // chunks from |wptr_| to |wptr_| + |bytes_to_clear|.
    523   // Returns:
    524   //   * The size of the gap left between the next valid Chunk and the end of
    525   //     the deletion range.
    526   //   * 0 if no next valid chunk exists (if the buffer is still zeroed).
    527   //   * -1 if the buffer |overwrite_policy_| == kDiscard and the deletion would
    528   //     cause unread chunks to be overwritten. In this case the buffer is left
    529   //     untouched.
    530   // Graphically, assume the initial situation is the following (|wptr_| = 10).
    531   // |0        |10 (wptr_)       |30       |40                 |60
    532   // +---------+-----------------+---------+-------------------+---------+
    533   // | Chunk 1 | Chunk 2         | Chunk 3 | Chunk 4           | Chunk 5 |
    534   // +---------+-----------------+---------+-------------------+---------+
    535   //           |_________Deletion range_______|~~return value~~|
    536   //
    537   // A call to DeleteNextChunksFor(32) will remove chunks 2,3,4 and return 18
    538   // (60 - 42), the distance between chunk 5 and the end of the deletion range.
    539   ssize_t DeleteNextChunksFor(size_t bytes_to_clear);
    540 
    541   // Decodes the boundaries of the next packet (or a fragment) pointed by
    542   // ChunkMeta and pushes that into |TracePacket|. It also increments the
    543   // |num_fragments_read| counter.
    544   // TracePacket can be nullptr, in which case the read state is still advanced.
    545   // When TracePacket is not nullptr, ProducerID must also be not null and will
    546   // be updated with the ProducerID that originally wrote the chunk.
    547   ReadPacketResult ReadNextPacketInChunk(ChunkMeta*, TracePacket*);
    548 
    549   void DcheckIsAlignedAndWithinBounds(const uint8_t* ptr) const {
    550     PERFETTO_DCHECK(ptr >= begin() && ptr <= end() - sizeof(ChunkRecord));
    551     PERFETTO_DCHECK(
    552         (reinterpret_cast<uintptr_t>(ptr) & (alignof(ChunkRecord) - 1)) == 0);
    553   }
    554 
    555   ChunkRecord* GetChunkRecordAt(uint8_t* ptr) {
    556     DcheckIsAlignedAndWithinBounds(ptr);
    557     // We may be accessing a new (empty) record.
    558     data_.EnsureCommitted(
    559         static_cast<size_t>(ptr + sizeof(ChunkRecord) - begin()));
    560     return reinterpret_cast<ChunkRecord*>(ptr);
    561   }
    562 
    563   void DiscardWrite();
    564 
    565   // |src| can be nullptr (in which case |size| must be ==
    566   // record.size - sizeof(ChunkRecord)), for the case of writing a padding
    567   // record. |wptr_| is NOT advanced by this function, the caller must do that.
    568   void WriteChunkRecord(uint8_t* wptr,
    569                         const ChunkRecord& record,
    570                         const uint8_t* src,
    571                         size_t size) {
    572     // Note: |record.size| will be slightly bigger than |size| because of the
    573     // ChunkRecord header and rounding, to ensure that all ChunkRecord(s) are
    574     // multiple of sizeof(ChunkRecord). The invariant is:
    575     // record.size >= |size| + sizeof(ChunkRecord) (== if no rounding).
    576     PERFETTO_DCHECK(size <= ChunkRecord::kMaxSize);
    577     PERFETTO_DCHECK(record.size >= sizeof(record));
    578     PERFETTO_DCHECK(record.size % sizeof(record) == 0);
    579     PERFETTO_DCHECK(record.size >= size + sizeof(record));
    580     PERFETTO_CHECK(record.size <= size_to_end());
    581     DcheckIsAlignedAndWithinBounds(wptr);
    582 
    583     // We may be writing to this area for the first time.
    584     data_.EnsureCommitted(static_cast<size_t>(wptr + record.size - begin()));
    585 
    586     // Deliberately not a *D*CHECK.
    587     PERFETTO_CHECK(wptr + sizeof(record) + size <= end());
    588     memcpy(wptr, &record, sizeof(record));
    589     if (PERFETTO_LIKELY(src)) {
    590       // If the producer modifies the data in the shared memory buffer while we
    591       // are copying it to the central buffer, TSAN will (rightfully) flag that
    592       // as a race. However the entire purpose of copying the data into the
    593       // central buffer is that we can validate it without worrying that the
    594       // producer changes it from under our feet, so this race is benign. The
    595       // alternative would be to try computing which part of the buffer is safe
    596       // to read (assuming a well-behaving client), but the risk of introducing
    597       // a bug that way outweighs the benefit.
    598       PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(
    599           src, size, "Benign race when copying chunk from shared memory.");
    600       memcpy(wptr + sizeof(record), src, size);
    601     } else {
    602       PERFETTO_DCHECK(size == record.size - sizeof(record));
    603     }
    604     const size_t rounding_size = record.size - sizeof(record) - size;
    605     memset(wptr + sizeof(record) + size, 0, rounding_size);
    606   }
    607 
    608   uint8_t* begin() const { return reinterpret_cast<uint8_t*>(data_.Get()); }
    609   uint8_t* end() const { return begin() + size_; }
    610   size_t size_to_end() const { return static_cast<size_t>(end() - wptr_); }
    611 
    612   base::PagedMemory data_;
    613   size_t size_ = 0;            // Size in bytes of |data_|.
    614   size_t max_chunk_size_ = 0;  // Max size in bytes allowed for a chunk.
    615   uint8_t* wptr_ = nullptr;    // Write pointer.
    616 
    617   // An index that keeps track of the positions and metadata of each
    618   // ChunkRecord.
    619   ChunkMap index_;
    620 
    621   // Read iterator used for ReadNext(). It is reset by calling BeginRead().
    622   // It becomes invalid after any call to methods that alters the |index_|.
    623   SequenceIterator read_iter_;
    624 
    625   // See comments at the top of the file.
    626   OverwritePolicy overwrite_policy_ = kOverwrite;
    627 
    628   // Only used when |overwrite_policy_ == kDiscard|. This is set the first time
    629   // a write fails because it would overwrite unread chunks.
    630   bool discard_writes_ = false;
    631 
    632   // Keeps track of the highest ChunkID written for a given sequence, taking
    633   // into account a potential overflow of ChunkIDs. In the case of overflow,
    634   // stores the highest ChunkID written since the overflow.
    635   //
    636   // TODO(primiano): should clean up keys from this map. Right now it grows
    637   // without bounds (although realistically is not a problem unless we have too
    638   // many producers/writers within the same trace session).
    639   std::map<std::pair<ProducerID, WriterID>, ChunkID> last_chunk_id_written_;
    640 
    641   // Statistics about buffer usage.
    642   TraceStats::BufferStats stats_;
    643 
    644 #if PERFETTO_DCHECK_IS_ON()
    645   bool changed_since_last_read_ = false;
    646 #endif
    647 
    648   // When true disable some DCHECKs that have been put in place to detect
    649   // bugs in the producers. This is for tests that feed malicious inputs and
    650   // hence mimic a buggy producer.
    651   bool suppress_sanity_dchecks_for_testing_ = false;
    652 };
    653 
    654 }  // namespace perfetto
    655 
    656 #endif  // SRC_TRACING_CORE_TRACE_BUFFER_H_
    657