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