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 #include "src/tracing/core/trace_writer_for_testing.h"
18 
19 #include "perfetto/base/logging.h"
20 #include "perfetto/base/utils.h"
21 #include "perfetto/protozero/message.h"
22 #include "perfetto/trace/trace.pb.h"
23 #include "perfetto/trace/trace.pbzero.h"
24 #include "perfetto/trace/trace_packet.pb.h"
25 #include "perfetto/trace/trace_packet.pbzero.h"
26 
27 namespace perfetto {
28 
TraceWriterForTesting()29 TraceWriterForTesting::TraceWriterForTesting()
30     : delegate_(static_cast<size_t>(base::kPageSize),
31                 static_cast<size_t>(base::kPageSize)),
32       stream_(&delegate_) {
33   delegate_.set_writer(&stream_);
34   cur_packet_.reset(new protos::pbzero::TracePacket());
35   cur_packet_->Finalize();  // To avoid the DCHECK in NewTracePacket().
36 }
37 
~TraceWriterForTesting()38 TraceWriterForTesting::~TraceWriterForTesting() {}
39 
Flush(std::function<void ()> callback)40 void TraceWriterForTesting::Flush(std::function<void()> callback) {
41   // Flush() cannot be called in the middle of a TracePacket.
42   PERFETTO_CHECK(cur_packet_->is_finalized());
43 
44   if (callback)
45     callback();
46 }
47 
GetAllTracePackets()48 std::vector<protos::TracePacket> TraceWriterForTesting::GetAllTracePackets() {
49   PERFETTO_CHECK(cur_packet_->is_finalized());
50 
51   auto trace = protos::Trace();
52   std::vector<uint8_t> buffer = delegate_.StitchSlices();
53   if (!trace.ParseFromArray(buffer.data(), static_cast<int>(buffer.size())))
54     return {};
55 
56   std::vector<protos::TracePacket> ret;
57   for (const auto& packet : trace.packet()) {
58     ret.emplace_back(packet);
59   }
60   return ret;
61 }
62 
ParseProto()63 std::unique_ptr<protos::TracePacket> TraceWriterForTesting::ParseProto() {
64   PERFETTO_CHECK(cur_packet_->is_finalized());
65 
66   auto trace = GetAllTracePackets();
67   PERFETTO_CHECK(!trace.empty());
68   auto packet =
69       std::unique_ptr<protos::TracePacket>(new protos::TracePacket(trace[0]));
70   return packet;
71 }
72 
73 TraceWriterForTesting::TracePacketHandle
NewTracePacket()74 TraceWriterForTesting::NewTracePacket() {
75   // If we hit this, the caller is calling NewTracePacket() without having
76   // finalized the previous packet.
77   PERFETTO_DCHECK(cur_packet_->is_finalized());
78   cur_packet_->Reset(&stream_);
79 
80   // Instead of storing the contents of the TracePacket directly in the backing
81   // buffer like the real trace writers, we prepend the proto preamble to make
82   // the buffer contents parsable as a sequence of TracePacket protos.
83 
84   uint8_t data[protozero::proto_utils::kMaxTagEncodedSize];
85   uint8_t* data_end = protozero::proto_utils::WriteVarInt(
86       protozero::proto_utils::MakeTagLengthDelimited(
87           protos::pbzero::Trace::kPacketFieldNumber),
88       data);
89   stream_.WriteBytes(data, static_cast<uint32_t>(data_end - data));
90 
91   auto packet = TraceWriter::TracePacketHandle(cur_packet_.get());
92   packet->set_size_field(
93       stream_.ReserveBytes(protozero::proto_utils::kMessageLengthFieldSize));
94   return packet;
95 }
96 
writer_id() const97 WriterID TraceWriterForTesting::writer_id() const {
98   return 0;
99 }
100 
written() const101 uint64_t TraceWriterForTesting::written() const {
102   return 0;
103 }
104 
105 }  // namespace perfetto
106