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 #include "perfetto/tracing/core/trace_packet.h"
18 
19 #include <string>
20 
21 #include "gtest/gtest.h"
22 
23 #include "perfetto/trace/trace.pb.h"
24 #include "perfetto/trace/trace_packet.pb.h"
25 #include "perfetto/trace/trusted_packet.pb.h"
26 
27 namespace perfetto {
28 namespace {
29 
30 static_assert(TracePacket::kPacketFieldNumber ==
31                   protos::Trace::kPacketFieldNumber,
32               "packet field id mismatch");
33 
34 static_assert(protos::TracePacket::kTrustedUidFieldNumber ==
35                   protos::TrustedPacket::kTrustedUidFieldNumber,
36               "trusted_uid field id mismatch");
37 
38 static_assert(protos::TracePacket::kTraceConfigFieldNumber ==
39                   protos::TrustedPacket::kTraceConfigFieldNumber,
40               "trace_config field id mismatch");
41 
42 static_assert(protos::TracePacket::kTraceStatsFieldNumber ==
43                   protos::TrustedPacket::kTraceStatsFieldNumber,
44               "trace_stats field id mismatch");
45 
46 static_assert(protos::TracePacket::kClockSnapshotFieldNumber ==
47                   protos::TrustedPacket::kClockSnapshotFieldNumber,
48               "clock_snapshot field id mismatch");
49 
TEST(TracePacketTest,Simple)50 TEST(TracePacketTest, Simple) {
51   protos::TracePacket proto;
52   proto.mutable_for_testing()->set_str("string field");
53   std::string ser_buf = proto.SerializeAsString();
54   TracePacket tp;
55   tp.AddSlice(ser_buf.data(), ser_buf.size());
56   auto slice = tp.slices().begin();
57   ASSERT_NE(tp.slices().end(), slice);
58   ASSERT_EQ(ser_buf.data(), slice->start);
59   ASSERT_EQ(ser_buf.size(), slice->size);
60   ASSERT_EQ(tp.slices().end(), ++slice);
61 
62   protos::TracePacket decoded_packet;
63   ASSERT_TRUE(tp.Decode(&decoded_packet));
64   ASSERT_EQ(proto.for_testing().str(), decoded_packet.for_testing().str());
65 }
66 
TEST(TracePacketTest,Sliced)67 TEST(TracePacketTest, Sliced) {
68   protos::TracePacket proto;
69   proto.mutable_for_testing()->set_str(
70       "this is an arbitrarily long string ........................");
71   std::string ser_buf = proto.SerializeAsString();
72   TracePacket tp;
73   tp.AddSlice({ser_buf.data(), 3});
74   tp.AddSlice({ser_buf.data() + 3, 5});
75   tp.AddSlice({ser_buf.data() + 3 + 5, ser_buf.size() - 3 - 5});
76   ASSERT_EQ(ser_buf.size(), tp.size());
77 
78   auto slice = tp.slices().begin();
79   ASSERT_NE(tp.slices().end(), slice);
80   ASSERT_EQ(ser_buf.data(), slice->start);
81   ASSERT_EQ(3u, slice->size);
82 
83   ASSERT_NE(tp.slices().end(), ++slice);
84   ASSERT_EQ(ser_buf.data() + 3, slice->start);
85   ASSERT_EQ(5u, slice->size);
86 
87   ASSERT_NE(tp.slices().end(), ++slice);
88   ASSERT_EQ(ser_buf.data() + 3 + 5, slice->start);
89   ASSERT_EQ(ser_buf.size() - 3 - 5, slice->size);
90 
91   ASSERT_EQ(tp.slices().end(), ++slice);
92 
93   protos::TracePacket decoded_packet;
94   ASSERT_TRUE(tp.Decode(&decoded_packet));
95   ASSERT_EQ(proto.for_testing().str(), decoded_packet.for_testing().str());
96 }
97 
TEST(TracePacketTest,Corrupted)98 TEST(TracePacketTest, Corrupted) {
99   protos::TracePacket proto;
100   proto.mutable_for_testing()->set_str("string field");
101   std::string ser_buf = proto.SerializeAsString();
102   TracePacket tp;
103   tp.AddSlice({ser_buf.data(), ser_buf.size() - 2});  // corrupted.
104   protos::TracePacket decoded_packet;
105   ASSERT_FALSE(tp.Decode(&decoded_packet));
106 }
107 
108 // Tests that the GetProtoPreamble() logic returns a valid preamble that allows
109 // to encode a TracePacket as a field of the root trace.proto message.
TEST(TracePacketTest,GetProtoPreamble)110 TEST(TracePacketTest, GetProtoPreamble) {
111   char* preamble;
112   size_t preamble_size;
113 
114   // Test empty packet.
115   TracePacket tp;
116   std::tie(preamble, preamble_size) = tp.GetProtoPreamble();
117   ASSERT_EQ(2u, preamble_size);
118   ASSERT_EQ(0, preamble[1]);
119 
120   // Test packet with one slice.
121   protos::TracePacket tp_proto;
122   char payload[257];
123   for (size_t i = 0; i < sizeof(payload) - 1; i++)
124     payload[i] = 'a' + (i % 16);
125   payload[sizeof(payload) - 1] = '\0';
126   tp_proto.mutable_for_testing()->set_str(payload);
127   std::string ser_buf = tp_proto.SerializeAsString();
128   tp.AddSlice({ser_buf.data(), ser_buf.size()});
129 
130   std::tie(preamble, preamble_size) = tp.GetProtoPreamble();
131   ASSERT_EQ(3u, preamble_size);
132 
133   // Verify that the content is actually parsable using libprotobuf.
134   char buf[512];
135   memcpy(buf, preamble, preamble_size);
136   ASSERT_EQ(1u, tp.slices().size());
137   memcpy(&buf[preamble_size], tp.slices()[0].start, tp.slices()[0].size);
138   protos::Trace trace;
139   ASSERT_TRUE(
140       trace.ParseFromArray(buf, static_cast<int>(preamble_size + tp.size())));
141   ASSERT_EQ(1, trace.packet_size());
142   ASSERT_EQ(payload, trace.packet(0).for_testing().str());
143 }
144 
TEST(TracePacketTest,MoveOperators)145 TEST(TracePacketTest, MoveOperators) {
146   char buf1[5]{};
147   char buf2[7]{};
148 
149   TracePacket tp;
150   tp.AddSlice(buf1, sizeof(buf1));
151   tp.AddSlice(buf2, sizeof(buf2));
152   tp.AddSlice(Slice::Allocate(11));
153   tp.AddSlice(Slice(std::unique_ptr<std::string>(new std::string("foobar"))));
154 
155   TracePacket moved_tp(std::move(tp));
156   ASSERT_EQ(0u, tp.size());
157   ASSERT_TRUE(tp.slices().empty());
158   ASSERT_EQ(4u, moved_tp.slices().size());
159   ASSERT_EQ(5u + 7u + 11u + 6u, moved_tp.size());
160 
161   TracePacket moved_tp_2;
162   moved_tp_2 = std::move(moved_tp);
163   ASSERT_EQ(0u, moved_tp.size());
164   ASSERT_TRUE(moved_tp.slices().empty());
165   ASSERT_EQ(4u, moved_tp_2.slices().size());
166   ASSERT_EQ(5u + 7u + 11u + 6u, moved_tp_2.size());
167 }
168 
169 }  // namespace
170 }  // namespace perfetto
171