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 "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
18 #include <cstddef>
19 
20 #include "src/trace_processor/importers/proto/track_event_sequence_state.h"
21 #include "src/trace_processor/storage/stats.h"
22 #include "src/trace_processor/storage/trace_storage.h"
23 #include "src/trace_processor/types/trace_processor_context.h"
24 
25 namespace perfetto::trace_processor {
26 
27 PacketSequenceStateGeneration::CustomState::~CustomState() = default;
28 
29 // static
30 RefPtr<PacketSequenceStateGeneration>
CreateFirst(TraceProcessorContext * context)31 PacketSequenceStateGeneration::CreateFirst(TraceProcessorContext* context) {
32   return RefPtr<PacketSequenceStateGeneration>(
33       new PacketSequenceStateGeneration(
34           context, TrackEventSequenceState::CreateFirst(), false));
35 }
36 
PacketSequenceStateGeneration(TraceProcessorContext * context,InternedFieldMap interned_data,TrackEventSequenceState track_event_sequence_state,CustomStateArray custom_state,TraceBlobView trace_packet_defaults,bool is_incremental_state_valid)37 PacketSequenceStateGeneration::PacketSequenceStateGeneration(
38     TraceProcessorContext* context,
39     InternedFieldMap interned_data,
40     TrackEventSequenceState track_event_sequence_state,
41     CustomStateArray custom_state,
42     TraceBlobView trace_packet_defaults,
43     bool is_incremental_state_valid)
44     : context_(context),
45       interned_data_(std::move(interned_data)),
46       track_event_sequence_state_(std::move(track_event_sequence_state)),
47       custom_state_(std::move(custom_state)),
48       trace_packet_defaults_(std::move(trace_packet_defaults)),
49       is_incremental_state_valid_(is_incremental_state_valid) {
50   for (auto& s : custom_state_) {
51     if (s.get() != nullptr) {
52       s->set_generation(this);
53     }
54   }
55 }
56 
57 RefPtr<PacketSequenceStateGeneration>
OnPacketLoss()58 PacketSequenceStateGeneration::OnPacketLoss() {
59   // No need to increment the generation. If any future packet depends on
60   // previous messages to update the incremental state its packet (if the
61   // DataSource is behaving correctly) would have the
62   // SEQ_NEEDS_INCREMENTAL_STATE bit set and such a packet will be dropped by
63   // the ProtoTraceReader and never make it far enough to update any incremental
64   // state.
65   track_event_sequence_state_.OnPacketLoss();
66   is_incremental_state_valid_ = false;
67   return RefPtr<PacketSequenceStateGeneration>(this);
68 }
69 
70 RefPtr<PacketSequenceStateGeneration>
OnIncrementalStateCleared()71 PacketSequenceStateGeneration::OnIncrementalStateCleared() {
72   return RefPtr<PacketSequenceStateGeneration>(
73       new PacketSequenceStateGeneration(
74           context_, track_event_sequence_state_.OnIncrementalStateCleared(),
75           true));
76 }
77 
78 RefPtr<PacketSequenceStateGeneration>
OnNewTracePacketDefaults(TraceBlobView trace_packet_defaults)79 PacketSequenceStateGeneration::OnNewTracePacketDefaults(
80     TraceBlobView trace_packet_defaults) {
81   return RefPtr<PacketSequenceStateGeneration>(
82       new PacketSequenceStateGeneration(
83           context_, interned_data_,
84           track_event_sequence_state_.OnIncrementalStateCleared(),
85           custom_state_, std::move(trace_packet_defaults),
86           is_incremental_state_valid_));
87 }
88 
GetInternedMessageView(uint32_t field_id,uint64_t iid)89 InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
90     uint32_t field_id,
91     uint64_t iid) {
92   auto field_it = interned_data_.find(field_id);
93   if (field_it != interned_data_.end()) {
94     auto* message_map = &field_it->second;
95     auto it = message_map->find(iid);
96     if (it != message_map->end()) {
97       return &it->second;
98     }
99   }
100 
101   context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
102   return nullptr;
103 }
104 
InternMessage(uint32_t field_id,TraceBlobView message)105 void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
106                                                   TraceBlobView message) {
107   constexpr auto kIidFieldNumber = 1;
108 
109   uint64_t iid = 0;
110   auto message_start = message.data();
111   auto message_size = message.length();
112   protozero::ProtoDecoder decoder(message_start, message_size);
113 
114   auto field = decoder.FindField(kIidFieldNumber);
115   if (PERFETTO_UNLIKELY(!field)) {
116     PERFETTO_DLOG("Interned message without interning_id");
117     context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
118     return;
119   }
120   iid = field.as_uint64();
121 
122   auto res = interned_data_[field_id].emplace(
123       iid, InternedMessageView(std::move(message)));
124 
125   // If a message with this ID is already interned in the same generation,
126   // its data should not have changed (this is forbidden by the InternedData
127   // proto).
128   // TODO(eseckler): This DCHECK assumes that the message is encoded the
129   // same way if it is re-emitted.
130   PERFETTO_DCHECK(res.second ||
131                   (res.first->second.message().length() == message_size &&
132                    memcmp(res.first->second.message().data(), message_start,
133                           message_size) == 0));
134 }
135 
136 }  // namespace perfetto::trace_processor
137