xref: /aosp_15_r20/external/perfetto/src/trace_redaction/process_thread_timeline.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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_redaction/process_thread_timeline.h"
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 
23 #include "perfetto/base/logging.h"
24 
25 namespace perfetto::trace_redaction {
26 namespace {
27 // Limit the number of iterations to avoid an infinite loop. 10 is a generous
28 // number of iterations.
29 constexpr size_t kMaxSearchDepth = 10;
30 
OrderByPid(const ProcessThreadTimeline::Event & left,const ProcessThreadTimeline::Event & right)31 bool OrderByPid(const ProcessThreadTimeline::Event& left,
32                 const ProcessThreadTimeline::Event& right) {
33   return left.pid < right.pid;
34 }
35 
36 }  // namespace
37 
Append(const Event & event)38 void ProcessThreadTimeline::Append(const Event& event) {
39   events_.push_back(event);
40   mode_ = Mode::kWrite;
41 }
42 
Sort()43 void ProcessThreadTimeline::Sort() {
44   std::sort(events_.begin(), events_.end(), OrderByPid);
45   mode_ = Mode::kRead;
46 }
47 
GetOpeningEvent(uint64_t ts,int32_t pid) const48 const ProcessThreadTimeline::Event* ProcessThreadTimeline::GetOpeningEvent(
49     uint64_t ts,
50     int32_t pid) const {
51   PERFETTO_DCHECK(mode_ == Mode::kRead);
52 
53   auto prev_open = QueryLeftMax(ts, pid, Event::Type::kOpen);
54   auto prev_close = QueryLeftMax(ts, pid, Event::Type::kClose);
55 
56   // If there is no open event before ts, it means pid never started.
57   if (!prev_open) {
58     return nullptr;
59   }
60 
61   // There is a close event that is strictly between the open event and ts, then
62   // the pid is considered free.
63   //
64   //    |---------|  ^  : pid is free
65   // ^  |---------|  ^  : pid is free
66   //    ^---------|     : pid is active
67   //    |---------^     : pid is active
68   //    |----^----|     : pid is active
69 
70   // Both open and close are less than or equal to ts (QueryLeftMax).
71   uint64_t close = prev_close ? prev_close->ts : 0;
72   uint64_t open = prev_open->ts;
73 
74   return close > open && close < ts ? nullptr : prev_open;
75 }
76 
PidConnectsToUid(uint64_t ts,int32_t pid,uint64_t uid) const77 bool ProcessThreadTimeline::PidConnectsToUid(uint64_t ts,
78                                              int32_t pid,
79                                              uint64_t uid) const {
80   PERFETTO_DCHECK(mode_ == Mode::kRead);
81 
82   const auto* prev_open = QueryLeftMax(ts, pid, Event::Type::kOpen);
83   const auto* prev_close = QueryLeftMax(ts, pid, Event::Type::kClose);
84 
85   for (size_t d = 0; d < kMaxSearchDepth; ++d) {
86     // If there's no previous open event, it means this pid was never created.
87     // This should not happen.
88     if (!prev_open) {
89       return false;
90     }
91 
92     // This get tricky here. If done wrong, proc_free events will fail because
93     // they'll report as disconnected when they could be connected to the
94     // package. Inclusive bounds are used here. In context, if a task_newtask
95     // event happens at time T, the pid exists at time T. If a proc_free event
96     // happens at time T, the pid is "shutting down" at time T but still exists.
97     //
98     //    B         E     : B = begin
99     //    .         .       E = end
100     //    .         .
101     //    |---------|  ^  : pid is free
102     // ^  |---------|     : pid is free
103     //    ^---------|     : pid is active
104     //    |---------^     : pid is active
105     //    |----^----|     : pid is active
106 
107     // By definition, both open and close are less than or equal to ts
108     // (QueryLeftMax), so problem space is reduces.
109     auto close = prev_close ? prev_close->ts : 0;
110     auto open = prev_open->ts;
111 
112     if (close > open && close < ts) {
113       return false;  // Close is sitting between open and ts.
114     }
115 
116     // TODO(vaage): Normalize the uid values.
117     if (prev_open->uid == uid) {
118       return true;
119     }
120 
121     if (prev_open->ppid == Event::kUnknownPid) {
122       return false;  // If there is no parent, there is no way to keep
123                      // searching.
124     }
125 
126     auto ppid = prev_open->ppid;
127 
128     prev_open = QueryLeftMax(ts, ppid, Event::Type::kOpen);
129     prev_close = QueryLeftMax(ts, ppid, Event::Type::kClose);
130   }
131 
132   return false;
133 }
134 
QueryLeftMax(uint64_t ts,int32_t pid,Event::Type type) const135 const ProcessThreadTimeline::Event* ProcessThreadTimeline::QueryLeftMax(
136     uint64_t ts,
137     int32_t pid,
138     Event::Type type) const {
139   auto fake = Event::Close(0, pid);
140 
141   // Events are sorted by pid, creating islands of data. This search is to put
142   // the cursor at the start of pid's island. Each island will be small (a
143   // couple of items), so searching within the islands should be cheap.
144   auto it = std::lower_bound(events_.begin(), events_.end(), fake, OrderByPid);
145   auto end = std::upper_bound(events_.begin(), events_.end(), fake, OrderByPid);
146 
147   const Event* best = nullptr;
148 
149   for (; it != end; ++it) {
150     bool replace = false;
151 
152     if (it->type == type && it->ts <= ts) {
153       replace = !best || it->ts > best->ts;
154     }
155 
156     if (replace) {
157       best = &(*it);
158     }
159   }
160 
161   return best;
162 }
163 
164 }  // namespace perfetto::trace_redaction
165