• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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/trace_processor/importers/proto/metadata_module.h"
18 
19 #include "perfetto/ext/base/base64.h"
20 #include "perfetto/ext/base/string_utils.h"
21 #include "perfetto/ext/base/uuid.h"
22 #include "src/trace_processor/importers/common/metadata_tracker.h"
23 #include "src/trace_processor/importers/common/slice_tracker.h"
24 #include "src/trace_processor/importers/common/track_tracker.h"
25 #include "src/trace_processor/importers/proto/config.descriptor.h"
26 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
27 #include "src/trace_processor/util/descriptors.h"
28 #include "src/trace_processor/util/protozero_to_text.h"
29 
30 #include "protos/perfetto/config/trace_config.pbzero.h"
31 #include "protos/perfetto/trace/chrome/chrome_trigger.pbzero.h"
32 #include "protos/perfetto/trace/trace_packet.pbzero.h"
33 #include "protos/perfetto/trace/trace_uuid.pbzero.h"
34 #include "protos/perfetto/trace/trigger.pbzero.h"
35 
36 namespace perfetto {
37 namespace trace_processor {
38 
39 using perfetto::protos::pbzero::TracePacket;
40 
MetadataModule(TraceProcessorContext * context)41 MetadataModule::MetadataModule(TraceProcessorContext* context)
42     : context_(context),
43       producer_name_key_id_(context_->storage->InternString("producer_name")),
44       trusted_producer_uid_key_id_(
45           context_->storage->InternString("trusted_producer_uid")) {
46   RegisterForField(TracePacket::kUiStateFieldNumber, context);
47   RegisterForField(TracePacket::kTriggerFieldNumber, context);
48   RegisterForField(TracePacket::kChromeTriggerFieldNumber, context);
49   RegisterForField(TracePacket::kTraceUuidFieldNumber, context);
50 }
51 
TokenizePacket(const protos::pbzero::TracePacket::Decoder & decoder,TraceBlobView *,int64_t,RefPtr<PacketSequenceStateGeneration>,uint32_t field_id)52 ModuleResult MetadataModule::TokenizePacket(
53     const protos::pbzero::TracePacket::Decoder& decoder,
54     TraceBlobView*,
55     int64_t,
56     RefPtr<PacketSequenceStateGeneration>,
57     uint32_t field_id) {
58   switch (field_id) {
59     case TracePacket::kUiStateFieldNumber: {
60       auto ui_state = decoder.ui_state();
61       std::string base64 = base::Base64Encode(ui_state.data, ui_state.size);
62       StringId id = context_->storage->InternString(base::StringView(base64));
63       context_->metadata_tracker->SetMetadata(metadata::ui_state,
64                                               Variadic::String(id));
65       return ModuleResult::Handled();
66     }
67     case TracePacket::kTraceUuidFieldNumber: {
68       // If both the TraceUuid packet and TraceConfig.trace_uuid_msb/lsb are
69       // set, the former (which is emitted first) takes precedence. This is
70       // because the UUID can change throughout the lifecycle of a tracing
71       // session if gap-less snapshots are used. Each trace file has at most one
72       // TraceUuid packet (i has if it comes from an older version of the
73       // tracing service < v32)
74       protos::pbzero::TraceUuid::Decoder uuid_packet(decoder.trace_uuid());
75       if (uuid_packet.msb() != 0 || uuid_packet.lsb() != 0) {
76         base::Uuid uuid(uuid_packet.lsb(), uuid_packet.msb());
77         std::string str = uuid.ToPrettyString();
78         StringId id = context_->storage->InternString(base::StringView(str));
79         context_->metadata_tracker->SetMetadata(metadata::trace_uuid,
80                                                 Variadic::String(id));
81         context_->uuid_found_in_trace = true;
82       }
83       return ModuleResult::Handled();
84     }
85   }
86   return ModuleResult::Ignored();
87 }
88 
ParseTracePacketData(const protos::pbzero::TracePacket::Decoder & decoder,int64_t ts,const TracePacketData &,uint32_t field_id)89 void MetadataModule::ParseTracePacketData(
90     const protos::pbzero::TracePacket::Decoder& decoder,
91     int64_t ts,
92     const TracePacketData&,
93     uint32_t field_id) {
94   // We handle triggers at parse time rather at tokenization because
95   // we add slices to tables which need to happen post-sorting.
96   if (field_id == TracePacket::kTriggerFieldNumber) {
97     ParseTrigger(ts, decoder.trigger());
98   }
99   if (field_id == TracePacket::kChromeTriggerFieldNumber) {
100     ParseChromeTrigger(ts, decoder.chrome_trigger());
101   }
102 }
103 
ParseTrigger(int64_t ts,ConstBytes blob)104 void MetadataModule::ParseTrigger(int64_t ts, ConstBytes blob) {
105   protos::pbzero::Trigger::Decoder trigger(blob.data, blob.size);
106   StringId cat_id = kNullStringId;
107   TrackId track_id = context_->track_tracker->GetOrCreateTriggerTrack();
108   StringId name_id = context_->storage->InternString(trigger.trigger_name());
109   context_->slice_tracker->Scoped(
110       ts, track_id, cat_id, name_id,
111       /* duration = */ 0,
112       [&trigger, this](ArgsTracker::BoundInserter* args_table) {
113         StringId producer_name =
114             context_->storage->InternString(trigger.producer_name());
115         if (!producer_name.is_null()) {
116           args_table->AddArg(producer_name_key_id_,
117                              Variadic::String(producer_name));
118         }
119         if (trigger.has_trusted_producer_uid()) {
120           args_table->AddArg(trusted_producer_uid_key_id_,
121                              Variadic::Integer(trigger.trusted_producer_uid()));
122         }
123       });
124 }
125 
ParseChromeTrigger(int64_t ts,ConstBytes blob)126 void MetadataModule::ParseChromeTrigger(int64_t ts, ConstBytes blob) {
127   protos::pbzero::ChromeTrigger::Decoder trigger(blob.data, blob.size);
128   StringId cat_id = kNullStringId;
129   TrackId track_id = context_->track_tracker->GetOrCreateTriggerTrack();
130   StringId name_id;
131   if (trigger.has_trigger_name()) {
132     name_id = context_->storage->InternString(trigger.trigger_name());
133   } else {
134     name_id = context_->storage->InternString(
135         base::StringView(base::IntToHexString(trigger.trigger_name_hash())));
136   }
137   context_->slice_tracker->Scoped(ts, track_id, cat_id, name_id,
138                                   /* duration = */ 0);
139 
140   MetadataTracker* metadata = context_->metadata_tracker.get();
141   metadata->SetDynamicMetadata(
142       context_->storage->InternString("cr-triggered_rule_name_hash"),
143       Variadic::Integer(trigger.trigger_name_hash()));
144 }
145 
ParseTraceUuid(ConstBytes blob)146 void MetadataModule::ParseTraceUuid(ConstBytes blob) {
147   // If both the TraceUuid packet and TraceConfig.trace_uuid_msb/lsb are set,
148   // the former (which is emitted first) takes precedence. This is because the
149   // UUID can change throughout the lifecycle of a tracing session if gap-less
150   // snapshots are used. Each trace file has at most one TraceUuid packet (i
151   // has if it comes from an older version of the tracing service < v32)
152   protos::pbzero::TraceUuid::Decoder uuid_packet(blob.data, blob.size);
153   if (uuid_packet.msb() != 0 || uuid_packet.lsb() != 0) {
154     base::Uuid uuid(uuid_packet.lsb(), uuid_packet.msb());
155     std::string str = uuid.ToPrettyString();
156     StringId id = context_->storage->InternString(base::StringView(str));
157     context_->metadata_tracker->SetMetadata(metadata::trace_uuid,
158                                             Variadic::String(id));
159     context_->uuid_found_in_trace = true;
160   }
161 }
162 
ParseTraceConfig(const protos::pbzero::TraceConfig_Decoder & trace_config)163 void MetadataModule::ParseTraceConfig(
164     const protos::pbzero::TraceConfig_Decoder& trace_config) {
165   int64_t uuid_msb = trace_config.trace_uuid_msb();
166   int64_t uuid_lsb = trace_config.trace_uuid_lsb();
167   if (!context_->uuid_found_in_trace && (uuid_msb != 0 || uuid_lsb != 0)) {
168     base::Uuid uuid(uuid_lsb, uuid_msb);
169     std::string str = uuid.ToPrettyString();
170     StringId id = context_->storage->InternString(base::StringView(str));
171     context_->metadata_tracker->SetMetadata(metadata::trace_uuid,
172                                             Variadic::String(id));
173     context_->uuid_found_in_trace = true;
174   }
175 
176   if (trace_config.has_unique_session_name()) {
177     StringId id = context_->storage->InternString(
178         base::StringView(trace_config.unique_session_name()));
179     context_->metadata_tracker->SetMetadata(metadata::unique_session_name,
180                                             Variadic::String(id));
181   }
182 
183   DescriptorPool pool;
184   pool.AddFromFileDescriptorSet(kConfigDescriptor.data(),
185                                 kConfigDescriptor.size());
186 
187   std::string text = protozero_to_text::ProtozeroToText(
188       pool, ".perfetto.protos.TraceConfig",
189       protozero::ConstBytes{
190           trace_config.begin(),
191           static_cast<uint32_t>(trace_config.end() - trace_config.begin())},
192       protozero_to_text::kIncludeNewLines);
193   StringId id = context_->storage->InternString(base::StringView(text));
194   context_->metadata_tracker->SetMetadata(metadata::trace_config_pbtxt,
195                                           Variadic::String(id));
196 }
197 
198 }  // namespace trace_processor
199 }  // namespace perfetto
200