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 #ifndef SRC_TRACING_CORE_TRACE_WRITER_IMPL_H_ 18 #define SRC_TRACING_CORE_TRACE_WRITER_IMPL_H_ 19 20 #include "perfetto/base/proc_utils.h" 21 #include "perfetto/ext/tracing/core/basic_types.h" 22 #include "perfetto/ext/tracing/core/shared_memory_abi.h" 23 #include "perfetto/ext/tracing/core/shared_memory_arbiter.h" 24 #include "perfetto/ext/tracing/core/trace_writer.h" 25 #include "perfetto/protozero/message_handle.h" 26 #include "perfetto/protozero/proto_utils.h" 27 #include "perfetto/protozero/root_message.h" 28 #include "perfetto/protozero/scattered_stream_writer.h" 29 #include "perfetto/tracing/buffer_exhausted_policy.h" 30 #include "src/tracing/core/patch_list.h" 31 32 namespace perfetto { 33 34 class SharedMemoryArbiterImpl; 35 36 // See //include/perfetto/ext/tracing/core/trace_writer.h for docs. 37 // 38 // Locking will happen only when a chunk is exhausted and a new one is 39 // acquired from the arbiter. 40 // 41 // TODO: TraceWriter needs to keep the shared memory buffer alive (refcount?). 42 // Otherwise if the shared memory buffer goes away (e.g. the Service crashes) 43 // the TraceWriter will keep writing into unmapped memory. 44 // 45 class TraceWriterImpl : public TraceWriter, 46 public protozero::MessageFinalizationListener, 47 public protozero::ScatteredStreamWriter::Delegate { 48 public: 49 // TracePacketHandle is defined in trace_writer.h 50 TraceWriterImpl(SharedMemoryArbiterImpl*, 51 WriterID, 52 MaybeUnboundBufferID buffer_id, 53 BufferExhaustedPolicy); 54 ~TraceWriterImpl() override; 55 56 // TraceWriter implementation. See documentation in trace_writer.h. 57 TracePacketHandle NewTracePacket() override; 58 void FinishTracePacket() override; 59 // Commits the data pending for the current chunk into the shared memory 60 // buffer and sends a CommitDataRequest() to the service. 61 // TODO(primiano): right now the |callback| will be called on the IPC thread. 62 // This is fine in the current single-thread scenario, but long-term 63 // trace_writer_impl.cc should be smarter and post it on the right thread. 64 void Flush(std::function<void()> callback = {}) override; 65 WriterID writer_id() const override; written()66 uint64_t written() const override { 67 return protobuf_stream_writer_.written(); 68 } 69 ResetChunkForTesting()70 void ResetChunkForTesting() { 71 cur_chunk_ = SharedMemoryABI::Chunk(); 72 cur_chunk_packet_count_inflated_ = false; 73 } drop_packets_for_testing()74 bool drop_packets_for_testing() const { return drop_packets_; } 75 76 private: 77 TraceWriterImpl(const TraceWriterImpl&) = delete; 78 TraceWriterImpl& operator=(const TraceWriterImpl&) = delete; 79 80 // ScatteredStreamWriter::Delegate implementation. 81 protozero::ContiguousMemoryRange GetNewBuffer() override; 82 uint8_t* AnnotatePatch(uint8_t*) override; 83 84 // MessageFinalizationListener implementation. 85 void OnMessageFinalized(protozero::Message*) override; 86 87 // Writes the size of the current fragment into the chunk. 88 // 89 // The size of nested messages inside TracePacket is written by 90 // by the user, but the size of the TracePacket fragments is written by 91 // TraceWriterImpl. 92 void FinalizeFragmentIfRequired(); 93 94 // Returns |cur_chunk_| (for which is_valid() must be true) to the 95 // |shmem_arbiter|. 96 void ReturnCompletedChunk(); 97 98 // The per-producer arbiter that coordinates access to the shared memory 99 // buffer from several threads. 100 SharedMemoryArbiterImpl* const shmem_arbiter_; 101 102 // ID of the current writer. 103 const WriterID id_; 104 105 // This is copied into the commit request by SharedMemoryArbiter. See comments 106 // in data_source_config.proto for |target_buffer|. If this is a reservation 107 // for a buffer ID in case of a startup trace writer, SharedMemoryArbiterImpl 108 // will also translate the reservation ID to the actual buffer ID. 109 const MaybeUnboundBufferID target_buffer_; 110 111 // Whether GetNewChunk() should stall or return an invalid chunk if the SMB is 112 // exhausted. 113 const BufferExhaustedPolicy buffer_exhausted_policy_; 114 115 // Monotonic (% wrapping) sequence id of the chunk. Together with the WriterID 116 // this allows the Service to reconstruct the linear sequence of packets. 117 ChunkID next_chunk_id_ = 0; 118 119 // The chunk we are holding onto (if any). 120 SharedMemoryABI::Chunk cur_chunk_; 121 122 // Passed to protozero message to write directly into |cur_chunk_|. It 123 // keeps track of the write pointer. It calls us back (GetNewBuffer()) when 124 // |cur_chunk_| is filled. 125 protozero::ScatteredStreamWriter protobuf_stream_writer_; 126 127 // The packet returned via NewTracePacket(). Its owned by this class, 128 // TracePacketHandle has just a pointer to it. 129 // 130 // The caller of NewTracePacket can use TakeStreamWriter() and use the stream 131 // writer directly: in that case: 132 // * cur_packet_->size() is not up to date. Only the stream writer has the 133 // correct information. 134 // * cur_packet_->nested_message() is always nullptr. 135 // * cur_packet_->size_field() is still used to track the start of the current 136 // fragment. 137 std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>> 138 cur_packet_; 139 140 // The start address of |cur_packet_| within |cur_chunk_|. Used to figure out 141 // fragments sizes when a TracePacket write is interrupted by GetNewBuffer(). 142 uint8_t* cur_fragment_start_ = nullptr; 143 144 // true if we received a call to GetNewBuffer() after NewTracePacket(), 145 // false if GetNewBuffer() happened during NewTracePacket() prologue, while 146 // starting the TracePacket header. 147 bool fragmenting_packet_ = false; 148 149 // Set to |true| when the current chunk contains the maximum number of packets 150 // a chunk can contain. When this is |true|, the next packet requires starting 151 // a new chunk. 152 bool reached_max_packets_per_chunk_ = false; 153 154 // If we fail to acquire a new chunk when the arbiter operates in 155 // SharedMemory::BufferExhaustedPolicy::kDrop mode, the trace writer enters a 156 // mode in which data is written to a local garbage chunk and dropped. 157 bool drop_packets_ = false; 158 159 // Whether the trace writer should try to acquire a new chunk from the SMB 160 // when the next TracePacket is started because it filled the garbage chunk at 161 // least once since the last attempt. 162 bool retry_new_chunk_after_packet_ = false; 163 164 // Set to true if `cur_chunk_` has a packet counter that's inflated by one. 165 // The count may be inflated to convince the tracing service scraping logic 166 // that the last packet has been completed. When this is true, cur_chunk_ 167 // should have at least `kExtraRoomForInflatedPacket` bytes free. 168 bool cur_chunk_packet_count_inflated_ = false; 169 170 // Points to the size field of the still open fragment we're writing to the 171 // current chunk. If the chunk was already returned, this is reset to 172 // |nullptr|. If the fragment is finalized, this is reset to |nullptr|. 173 // 174 // Note: for nested messages the field is tracked somewhere else 175 // (protozero::Message::size_field_ or PerfettoPbMsg::size_field). For the 176 // root message, protozero::Message::size_field_ is nullptr and this is used 177 // instead. This is because at the root level we deal with fragments, not 178 // logical messages. 179 uint8_t* cur_fragment_size_field_ = nullptr; 180 181 // When a packet is fragmented across different chunks, the |size_field| of 182 // the outstanding nested protobuf messages is redirected onto Patch entries 183 // in this list at the time the Chunk is returned (because at that point we 184 // have to release the ownership of the current Chunk). This list will be 185 // later sent out-of-band to the tracing service, who will patch the required 186 // chunks, if they are still around. 187 PatchList patch_list_; 188 189 // PID of the process that created the trace writer. Used for a DCHECK that 190 // aims to detect unsupported process forks while tracing. 191 const base::PlatformProcessId process_id_; 192 193 // True for the first packet on sequence. See the comment for 194 // TracePacket.first_packet_on_sequence for more details. 195 bool first_packet_on_sequence_ = true; 196 }; 197 198 } // namespace perfetto 199 200 #endif // SRC_TRACING_CORE_TRACE_WRITER_IMPL_H_ 201