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 drop_packets_for_testing()70 bool drop_packets_for_testing() const { return drop_packets_; } 71 72 private: 73 TraceWriterImpl(const TraceWriterImpl&) = delete; 74 TraceWriterImpl& operator=(const TraceWriterImpl&) = delete; 75 76 // ScatteredStreamWriter::Delegate implementation. 77 protozero::ContiguousMemoryRange GetNewBuffer() override; 78 uint8_t* AnnotatePatch(uint8_t*) override; 79 80 // MessageFinalizationListener implementation. 81 void OnMessageFinalized(protozero::Message*) override; 82 83 // Writes the size of the current fragment into the chunk. 84 // 85 // The size of nested messages inside TracePacket is written by 86 // by the user, but the size of the TracePacket fragments is written by 87 // TraceWriterImpl. 88 void FinalizeFragmentIfRequired(); 89 90 // Returns |cur_chunk_| (for which is_valid() must be true) to the 91 // |shmem_arbiter|. 92 void ReturnCompletedChunk(); 93 94 // The per-producer arbiter that coordinates access to the shared memory 95 // buffer from several threads. 96 SharedMemoryArbiterImpl* const shmem_arbiter_; 97 98 // ID of the current writer. 99 const WriterID id_; 100 101 // This is copied into the commit request by SharedMemoryArbiter. See comments 102 // in data_source_config.proto for |target_buffer|. If this is a reservation 103 // for a buffer ID in case of a startup trace writer, SharedMemoryArbiterImpl 104 // will also translate the reservation ID to the actual buffer ID. 105 const MaybeUnboundBufferID target_buffer_; 106 107 // Whether GetNewChunk() should stall or return an invalid chunk if the SMB is 108 // exhausted. 109 const BufferExhaustedPolicy buffer_exhausted_policy_; 110 111 // Monotonic (% wrapping) sequence id of the chunk. Together with the WriterID 112 // this allows the Service to reconstruct the linear sequence of packets. 113 ChunkID next_chunk_id_ = 0; 114 115 // The chunk we are holding onto (if any). 116 SharedMemoryABI::Chunk cur_chunk_; 117 118 // Passed to protozero message to write directly into |cur_chunk_|. It 119 // keeps track of the write pointer. It calls us back (GetNewBuffer()) when 120 // |cur_chunk_| is filled. 121 protozero::ScatteredStreamWriter protobuf_stream_writer_; 122 123 // The packet returned via NewTracePacket(). Its owned by this class, 124 // TracePacketHandle has just a pointer to it. 125 // 126 // The caller of NewTracePacket can use TakeStreamWriter() and use the stream 127 // writer directly: in that case: 128 // * cur_packet_->size() is not up to date. Only the stream writer has the 129 // correct information. 130 // * cur_packet_->nested_message() is always nullptr. 131 // * cur_packet_->size_field() is still used to track the start of the current 132 // fragment. 133 std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>> 134 cur_packet_; 135 136 // The start address of |cur_packet_| within |cur_chunk_|. Used to figure out 137 // fragments sizes when a TracePacket write is interrupted by GetNewBuffer(). 138 uint8_t* cur_fragment_start_ = nullptr; 139 140 // true if we received a call to GetNewBuffer() after NewTracePacket(), 141 // false if GetNewBuffer() happened during NewTracePacket() prologue, while 142 // starting the TracePacket header. 143 bool fragmenting_packet_ = false; 144 145 // Set to |true| when the current chunk contains the maximum number of packets 146 // a chunk can contain. When this is |true|, the next packet requires starting 147 // a new chunk. 148 bool reached_max_packets_per_chunk_ = false; 149 150 // If we fail to acquire a new chunk when the arbiter operates in 151 // SharedMemory::BufferExhaustedPolicy::kDrop mode, the trace writer enters a 152 // mode in which data is written to a local garbage chunk and dropped. 153 bool drop_packets_ = false; 154 155 // Whether the trace writer should try to acquire a new chunk from the SMB 156 // when the next TracePacket is started because it filled the garbage chunk at 157 // least once since the last attempt. 158 bool retry_new_chunk_after_packet_ = false; 159 160 // Set to true if `cur_chunk_` has a packet counter that's inflated by one. 161 // The count may be inflated to convince the tracing service scraping logic 162 // that the last packet has been completed. When this is true, cur_chunk_ 163 // should have at least `kExtraRoomForInflatedPacket` bytes free. 164 bool cur_chunk_packet_count_inflated_ = false; 165 166 // Points to the size field of the still open fragment we're writing to the 167 // current chunk. If the chunk was already returned, this is reset to 168 // |nullptr|. If the fragment is finalized, this is reset to |nullptr|. 169 // 170 // Note: for nested messages the field is tracked somewhere else 171 // (protozero::Message::size_field_ or PerfettoPbMsg::size_field). For the 172 // root message, protozero::Message::size_field_ is nullptr and this is used 173 // instead. This is because at the root level we deal with fragments, not 174 // logical messages. 175 uint8_t* cur_fragment_size_field_ = nullptr; 176 177 // When a packet is fragmented across different chunks, the |size_field| of 178 // the outstanding nested protobuf messages is redirected onto Patch entries 179 // in this list at the time the Chunk is returned (because at that point we 180 // have to release the ownership of the current Chunk). This list will be 181 // later sent out-of-band to the tracing service, who will patch the required 182 // chunks, if they are still around. 183 PatchList patch_list_; 184 185 // PID of the process that created the trace writer. Used for a DCHECK that 186 // aims to detect unsupported process forks while tracing. 187 const base::PlatformProcessId process_id_; 188 189 // True for the first packet on sequence. See the comment for 190 // TracePacket.first_packet_on_sequence for more details. 191 bool first_packet_on_sequence_ = true; 192 }; 193 194 } // namespace perfetto 195 196 #endif // SRC_TRACING_CORE_TRACE_WRITER_IMPL_H_ 197