1 /*
2  * Copyright (C) 2020 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 "perfetto/tracing/internal/interceptor_trace_writer.h"
18 
19 #include "perfetto/ext/tracing/core/trace_writer.h"
20 
21 namespace perfetto {
22 namespace internal {
23 
24 // static
25 std::atomic<uint32_t> InterceptorTraceWriter::next_sequence_id_{};
26 
InterceptorTraceWriter(std::unique_ptr<InterceptorBase::ThreadLocalState> tls,InterceptorBase::TracePacketCallback packet_callback,DataSourceStaticState * static_state,uint32_t instance_index)27 InterceptorTraceWriter::InterceptorTraceWriter(
28     std::unique_ptr<InterceptorBase::ThreadLocalState> tls,
29     InterceptorBase::TracePacketCallback packet_callback,
30     DataSourceStaticState* static_state,
31     uint32_t instance_index)
32     : tls_(std::move(tls)),
33       packet_callback_(std::move(packet_callback)),
34       static_state_(static_state),
35       instance_index_(instance_index),
36       sequence_id_(++next_sequence_id_) {}
37 
38 InterceptorTraceWriter::~InterceptorTraceWriter() = default;
39 
40 protozero::MessageHandle<protos::pbzero::TracePacket>
NewTracePacket()41 InterceptorTraceWriter::NewTracePacket() {
42   Flush();
43   auto packet = TraceWriter::TracePacketHandle(cur_packet_.get());
44   packet->set_trusted_packet_sequence_id(sequence_id_);
45   return packet;
46 }
47 
Flush(std::function<void ()> callback)48 void InterceptorTraceWriter::Flush(std::function<void()> callback) {
49   if (!cur_packet_.empty()) {
50     InterceptorBase::TracePacketCallbackArgs args{};
51     args.static_state = static_state_;
52     args.instance_index = instance_index_;
53     args.tls = tls_.get();
54 
55     const auto& slices = cur_packet_.GetSlices();
56     if (slices.size() == 1) {
57       // Fast path: the current packet fits into a single slice.
58       auto slice_range = slices.begin()->GetUsedRange();
59       args.packet_data = protozero::ConstBytes{
60           slice_range.begin,
61           static_cast<size_t>(slice_range.end - slice_range.begin)};
62       bytes_written_ += static_cast<uint64_t>(args.packet_data.size);
63       packet_callback_(std::move(args));
64     } else {
65       // Fallback: stitch together multiple slices.
66       auto stitched_data = cur_packet_.SerializeAsArray();
67       args.packet_data =
68           protozero::ConstBytes{stitched_data.data(), stitched_data.size()};
69       bytes_written_ += static_cast<uint64_t>(stitched_data.size());
70       packet_callback_(std::move(args));
71     }
72     cur_packet_.Reset();
73   }
74   if (callback)
75     callback();
76 }
77 
written() const78 uint64_t InterceptorTraceWriter::written() const {
79   return bytes_written_;
80 }
81 
82 }  // namespace internal
83 }  // namespace perfetto
84