• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/trace_processor/importers/common/process_tracker.h"
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <optional>
22 #include <utility>
23 #include <vector>
24 
25 #include "perfetto/base/logging.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "perfetto/public/compiler.h"
28 #include "src/trace_processor/storage/stats.h"
29 #include "src/trace_processor/storage/trace_storage.h"
30 #include "src/trace_processor/tables/metadata_tables_py.h"
31 #include "src/trace_processor/types/trace_processor_context.h"
32 
33 namespace perfetto::trace_processor {
34 
ProcessTracker(TraceProcessorContext * context)35 ProcessTracker::ProcessTracker(TraceProcessorContext* context)
36     : context_(context), args_tracker_(context) {
37   // Reserve utid/upid 0. These are special as embedders (e.g. Perfetto UI)
38   // exclude them from certain views (e.g. thread state) under the assumption
39   // that they correspond to the idle (swapper) process. When parsing Linux
40   // system traces, SetPidZeroIsUpidZeroIdleProcess will be called to associate
41   // tid0/pid0 to utid0/upid0. If other types of traces refer to tid0/pid0,
42   // then they will get their own non-zero utid/upid, so that those threads are
43   // still surfaced in embedder UIs.
44   //
45   // Note on multi-machine tracing: utid/upid of the swapper process of
46   // secondary machine will not be 0. The ProcessTracker needs to insert to the
47   // thread and process tables to reserve utid and upid.
48   tables::ProcessTable::Row process_row;
49   process_row.pid = 0u;
50   process_row.machine_id = context_->machine_id();
51   auto upid =
52       context_->storage->mutable_process_table()->Insert(process_row).row;
53 
54   tables::ThreadTable::Row thread_row;
55   thread_row.tid = 0u;
56   thread_row.upid = upid;  // The swapper upid may be != 0 for remote machines.
57   thread_row.is_main_thread = true;
58   thread_row.machine_id = context_->machine_id();
59   auto utid = context_->storage->mutable_thread_table()->Insert(thread_row).row;
60 
61   swapper_upid_ = upid;
62   swapper_utid_ = utid;
63 
64   // An element to match the reserved tid = 0.
65   thread_name_priorities_.push_back(ThreadNamePriority::kOther);
66 }
67 
68 ProcessTracker::~ProcessTracker() = default;
69 
StartNewThread(std::optional<int64_t> timestamp,uint32_t tid)70 UniqueTid ProcessTracker::StartNewThread(std::optional<int64_t> timestamp,
71                                          uint32_t tid) {
72   tables::ThreadTable::Row row;
73   row.tid = tid;
74   row.start_ts = timestamp;
75   row.machine_id = context_->machine_id();
76 
77   auto* thread_table = context_->storage->mutable_thread_table();
78   UniqueTid new_utid = thread_table->Insert(row).row;
79   tids_[tid].emplace_back(new_utid);
80 
81   if (PERFETTO_UNLIKELY(thread_name_priorities_.size() <= new_utid)) {
82     // This condition can happen in a multi-machine tracing session:
83     // Machine 1 gets utid 0, 1
84     // Machine 2 gets utid 2, 3
85     // Machine 1 gets utid 4: where thread_name_priorities_.size() == 2.
86     thread_name_priorities_.resize(new_utid + 1);
87   }
88   thread_name_priorities_[new_utid] = ThreadNamePriority::kOther;
89   return new_utid;
90 }
91 
EndThread(int64_t timestamp,uint32_t tid)92 void ProcessTracker::EndThread(int64_t timestamp, uint32_t tid) {
93   auto* thread_table = context_->storage->mutable_thread_table();
94   auto* process_table = context_->storage->mutable_process_table();
95 
96   // Don't bother creating a new thread if we're just going to
97   // end it straight away.
98   //
99   // This is useful in situations where we get a sched_process_free event for a
100   // worker thread in a process *after* the main thread finishes - in that case
101   // we would have already ended the process and we don't want to
102   // create a new thread here (see b/193520421 for an example of a trace
103   // where this happens in practice).
104   std::optional<UniqueTid> opt_utid = GetThreadOrNull(tid);
105   if (!opt_utid)
106     return;
107 
108   UniqueTid utid = *opt_utid;
109   thread_table->mutable_end_ts()->Set(utid, timestamp);
110 
111   // Remove the thread from the list of threads being tracked as any event after
112   // this one should be ignored.
113   auto& vector = tids_[tid];
114   vector.erase(std::remove(vector.begin(), vector.end(), utid), vector.end());
115 
116   auto opt_upid = thread_table->upid()[utid];
117   if (!opt_upid.has_value() || process_table->pid()[*opt_upid] != tid)
118     return;
119 
120   // If the process pid and thread tid are equal then, as is the main thread
121   // of the process, we should also finish the process itself.
122   PERFETTO_DCHECK(thread_table->is_main_thread()[utid].value());
123   process_table->mutable_end_ts()->Set(*opt_upid, timestamp);
124   pids_.Erase(tid);
125 }
126 
GetThreadOrNull(uint32_t tid)127 std::optional<UniqueTid> ProcessTracker::GetThreadOrNull(uint32_t tid) {
128   auto opt_utid = GetThreadOrNull(tid, std::nullopt);
129   if (!opt_utid)
130     return std::nullopt;
131 
132   auto* threads = context_->storage->mutable_thread_table();
133   UniqueTid utid = *opt_utid;
134 
135   // Ensure that the tid matches the tid we were looking for.
136   PERFETTO_DCHECK(threads->tid()[utid] == tid);
137   // Ensure that the thread's machine ID matches the context's machine ID.
138   PERFETTO_DCHECK(threads->machine_id()[utid] == context_->machine_id());
139   // If the thread is being tracked by the process tracker, it should not be
140   // known to have ended.
141   PERFETTO_DCHECK(!threads->end_ts()[utid].has_value());
142 
143   return utid;
144 }
145 
GetOrCreateThread(uint32_t tid)146 UniqueTid ProcessTracker::GetOrCreateThread(uint32_t tid) {
147   auto utid = GetThreadOrNull(tid);
148   return utid ? *utid : StartNewThread(std::nullopt, tid);
149 }
150 
UpdateThreadName(uint32_t tid,StringId thread_name_id,ThreadNamePriority priority)151 UniqueTid ProcessTracker::UpdateThreadName(uint32_t tid,
152                                            StringId thread_name_id,
153                                            ThreadNamePriority priority) {
154   auto utid = GetOrCreateThread(tid);
155   UpdateThreadNameByUtid(utid, thread_name_id, priority);
156   return utid;
157 }
158 
UpdateThreadNameByUtid(UniqueTid utid,StringId thread_name_id,ThreadNamePriority priority)159 void ProcessTracker::UpdateThreadNameByUtid(UniqueTid utid,
160                                             StringId thread_name_id,
161                                             ThreadNamePriority priority) {
162   if (thread_name_id.is_null())
163     return;
164 
165   auto* thread_table = context_->storage->mutable_thread_table();
166   if (PERFETTO_UNLIKELY(thread_name_priorities_.size() <= utid)) {
167     // This condition can happen in a multi-machine tracing session:
168     // Machine 1 gets utid 0, 1
169     // Machine 2 gets utid 2, 3
170     // Machine 1 gets utid 4: where thread_name_priorities_.size() == 2.
171     thread_name_priorities_.resize(utid + 1);
172   }
173   if (priority >= thread_name_priorities_[utid]) {
174     thread_table->mutable_name()->Set(utid, thread_name_id);
175     thread_name_priorities_[utid] = priority;
176   }
177 }
178 
IsThreadAlive(UniqueTid utid)179 bool ProcessTracker::IsThreadAlive(UniqueTid utid) {
180   auto* threads = context_->storage->mutable_thread_table();
181   auto* processes = context_->storage->mutable_process_table();
182 
183   // If the thread has an end ts, it's certainly dead.
184   if (threads->end_ts()[utid].has_value())
185     return false;
186 
187   // If we don't know the parent process, we have to consider this thread alive.
188   auto opt_current_upid = threads->upid()[utid];
189   if (!opt_current_upid)
190     return true;
191 
192   // If the process is already dead, the thread can't be alive.
193   UniquePid current_upid = *opt_current_upid;
194   if (processes->end_ts()[current_upid].has_value())
195     return false;
196 
197   // If the process has been replaced in |pids_|, this thread is dead.
198   uint32_t current_pid = processes->pid()[current_upid];
199   auto* pid_it = pids_.Find(current_pid);
200   return !pid_it || *pid_it == current_upid;
201 }
202 
GetThreadOrNull(uint32_t tid,std::optional<uint32_t> pid)203 std::optional<UniqueTid> ProcessTracker::GetThreadOrNull(
204     uint32_t tid,
205     std::optional<uint32_t> pid) {
206   auto* threads = context_->storage->mutable_thread_table();
207   auto* processes = context_->storage->mutable_process_table();
208 
209   auto* vector_it = tids_.Find(tid);
210   if (!vector_it)
211     return std::nullopt;
212 
213   // Iterate backwards through the threads so ones later in the trace are more
214   // likely to be picked.
215   const auto& vector = *vector_it;
216   for (auto it = vector.rbegin(); it != vector.rend(); it++) {
217     UniqueTid current_utid = *it;
218 
219     // If we finished this thread, we should have removed it from the vector
220     // entirely.
221     PERFETTO_DCHECK(!threads->end_ts()[current_utid].has_value());
222 
223     // If the thread is dead, ignore it.
224     if (!IsThreadAlive(current_utid))
225       continue;
226 
227     // If we don't know the parent process, we have to choose this thread.
228     auto opt_current_upid = threads->upid()[current_utid];
229     if (!opt_current_upid)
230       return current_utid;
231 
232     // We found a thread that matches both the tid and its parent pid.
233     uint32_t current_pid = processes->pid()[*opt_current_upid];
234     if (!pid || current_pid == *pid)
235       return current_utid;
236   }
237   return std::nullopt;
238 }
239 
UpdateThread(uint32_t tid,uint32_t pid)240 UniqueTid ProcessTracker::UpdateThread(uint32_t tid, uint32_t pid) {
241   auto* thread_table = context_->storage->mutable_thread_table();
242 
243   // Try looking for a thread that matches both tid and thread group id (pid).
244   std::optional<UniqueTid> opt_utid = GetThreadOrNull(tid, pid);
245 
246   // If no matching thread was found, create a new one.
247   UniqueTid utid = opt_utid ? *opt_utid : StartNewThread(std::nullopt, tid);
248   PERFETTO_DCHECK(thread_table->tid()[utid] == tid);
249   // Ensure that the thread's machine ID matches the context's machine ID.
250   PERFETTO_DCHECK(thread_table->machine_id()[utid] == context_->machine_id());
251 
252   // Find matching process or create new one.
253   if (!thread_table->upid()[utid].has_value()) {
254     AssociateThreadToProcess(utid, GetOrCreateProcess(pid));
255   }
256 
257   ResolvePendingAssociations(utid, *thread_table->upid()[utid]);
258 
259   return utid;
260 }
261 
UpdateTrustedPid(uint32_t trusted_pid,uint64_t uuid)262 void ProcessTracker::UpdateTrustedPid(uint32_t trusted_pid, uint64_t uuid) {
263   trusted_pids_[uuid] = trusted_pid;
264 }
265 
GetTrustedPid(uint64_t uuid)266 std::optional<uint32_t> ProcessTracker::GetTrustedPid(uint64_t uuid) {
267   if (trusted_pids_.find(uuid) == trusted_pids_.end())
268     return std::nullopt;
269   return trusted_pids_[uuid];
270 }
271 
ResolveNamespacedTid(uint32_t root_level_pid,uint32_t tid)272 std::optional<uint32_t> ProcessTracker::ResolveNamespacedTid(
273     uint32_t root_level_pid,
274     uint32_t tid) {
275   if (root_level_pid <= 0)  // Not a valid pid.
276     return std::nullopt;
277 
278   // If the process doesn't run in a namespace (or traced_probes doesn't observe
279   // that), return std::nullopt as failure to resolve.
280   auto process_it = namespaced_processes_.find(root_level_pid);
281   if (process_it == namespaced_processes_.end())
282     return std::nullopt;
283 
284   // Check if it's the main thread.
285   const auto& process = process_it->second;
286   auto ns_level = process.nspid.size() - 1;
287   auto pid_local = process.nspid.back();
288   if (pid_local == tid)
289     return root_level_pid;
290 
291   // Check if any non-main thread has a matching ns-local thread ID.
292   for (const auto& root_level_tid : process.threads) {
293     const auto& thread = namespaced_threads_[root_level_tid];
294     PERFETTO_DCHECK(thread.nstid.size() > ns_level);
295     auto tid_ns_local = thread.nstid[ns_level];
296     if (tid_ns_local == tid)
297       return thread.tid;
298   }
299 
300   // Failed to resolve or the thread isn't namespaced
301   return std::nullopt;
302 }
303 
StartNewProcess(std::optional<int64_t> timestamp,std::optional<uint32_t> parent_tid,uint32_t pid,StringId main_thread_name,ThreadNamePriority priority)304 UniquePid ProcessTracker::StartNewProcess(std::optional<int64_t> timestamp,
305                                           std::optional<uint32_t> parent_tid,
306                                           uint32_t pid,
307                                           StringId main_thread_name,
308                                           ThreadNamePriority priority) {
309   pids_.Erase(pid);
310   // TODO(eseckler): Consider erasing all old entries in |tids_| that match the
311   // |pid| (those would be for an older process with the same pid). Right now,
312   // we keep them in |tids_| (if they weren't erased by EndThread()), but ignore
313   // them in GetThreadOrNull().
314 
315   // Create a new UTID for the main thread, so we don't end up reusing an old
316   // entry in case of TID recycling.
317   UniqueTid utid = StartNewThread(timestamp, /*tid=*/pid);
318   UpdateThreadNameByUtid(utid, main_thread_name, priority);
319 
320   // Note that we erased the pid above so this should always return a new
321   // process.
322   UniquePid upid = GetOrCreateProcess(pid);
323 
324   auto* process_table = context_->storage->mutable_process_table();
325   auto* thread_table = context_->storage->mutable_thread_table();
326 
327   PERFETTO_DCHECK(!process_table->name()[upid].has_value());
328   PERFETTO_DCHECK(!process_table->start_ts()[upid].has_value());
329 
330   if (timestamp) {
331     process_table->mutable_start_ts()->Set(upid, *timestamp);
332   }
333   process_table->mutable_name()->Set(upid, main_thread_name);
334 
335   if (parent_tid) {
336     UniqueTid parent_utid = GetOrCreateThread(*parent_tid);
337     auto opt_parent_upid = thread_table->upid()[parent_utid];
338     if (opt_parent_upid.has_value()) {
339       process_table->mutable_parent_upid()->Set(upid, *opt_parent_upid);
340     } else {
341       pending_parent_assocs_.emplace_back(parent_utid, upid);
342     }
343   }
344   return upid;
345 }
346 
SetProcessMetadata(uint32_t pid,std::optional<uint32_t> ppid,base::StringView name,base::StringView cmdline)347 UniquePid ProcessTracker::SetProcessMetadata(uint32_t pid,
348                                              std::optional<uint32_t> ppid,
349                                              base::StringView name,
350                                              base::StringView cmdline) {
351   std::optional<UniquePid> pupid;
352   if (ppid.has_value()) {
353     pupid = GetOrCreateProcess(ppid.value());
354   }
355 
356   UniquePid upid = GetOrCreateProcess(pid);
357   auto* process_table = context_->storage->mutable_process_table();
358 
359   // If we both know the previous and current parent pid and the two are not
360   // matching, we must have died and restarted: create a new process.
361   if (pupid) {
362     std::optional<UniquePid> prev_parent_upid =
363         process_table->parent_upid()[upid];
364     if (prev_parent_upid && prev_parent_upid != pupid) {
365       upid = StartNewProcess(std::nullopt, ppid, pid, kNullStringId,
366                              ThreadNamePriority::kOther);
367     }
368   }
369 
370   StringId proc_name_id = context_->storage->InternString(name);
371   process_table->mutable_name()->Set(upid, proc_name_id);
372   process_table->mutable_cmdline()->Set(
373       upid, context_->storage->InternString(cmdline));
374   if (pupid)
375     process_table->mutable_parent_upid()->Set(upid, *pupid);
376 
377   return upid;
378 }
379 
SetProcessUid(UniquePid upid,uint32_t uid)380 void ProcessTracker::SetProcessUid(UniquePid upid, uint32_t uid) {
381   auto* process_table = context_->storage->mutable_process_table();
382   process_table->mutable_uid()->Set(upid, uid);
383 
384   // The notion of the app ID (as derived from the uid) is defined in
385   // frameworks/base/core/java/android/os/UserHandle.java
386   process_table->mutable_android_appid()->Set(upid, uid % 100000);
387 }
388 
SetProcessNameIfUnset(UniquePid upid,StringId process_name_id)389 void ProcessTracker::SetProcessNameIfUnset(UniquePid upid,
390                                            StringId process_name_id) {
391   auto* process_table = context_->storage->mutable_process_table();
392   if (!process_table->name()[upid].has_value())
393     process_table->mutable_name()->Set(upid, process_name_id);
394 }
395 
SetStartTsIfUnset(UniquePid upid,int64_t start_ts_nanoseconds)396 void ProcessTracker::SetStartTsIfUnset(UniquePid upid,
397                                        int64_t start_ts_nanoseconds) {
398   auto* process_table = context_->storage->mutable_process_table();
399   if (!process_table->start_ts()[upid].has_value())
400     process_table->mutable_start_ts()->Set(upid, start_ts_nanoseconds);
401 }
402 
UpdateThreadNameAndMaybeProcessName(uint32_t tid,StringId thread_name,ThreadNamePriority priority)403 void ProcessTracker::UpdateThreadNameAndMaybeProcessName(
404     uint32_t tid,
405     StringId thread_name,
406     ThreadNamePriority priority) {
407   auto* thread_table = context_->storage->mutable_thread_table();
408   auto* process_table = context_->storage->mutable_process_table();
409 
410   UniqueTid utid = UpdateThreadName(tid, thread_name, priority);
411   std::optional<UniquePid> opt_upid = thread_table->upid()[utid];
412   if (opt_upid.has_value() && process_table->pid()[*opt_upid] == tid) {
413     PERFETTO_DCHECK(thread_table->is_main_thread()[utid]);
414     process_table->mutable_name()->Set(*opt_upid, thread_name);
415   }
416 }
417 
GetOrCreateProcess(uint32_t pid)418 UniquePid ProcessTracker::GetOrCreateProcess(uint32_t pid) {
419   auto* process_table = context_->storage->mutable_process_table();
420 
421   // If the insertion succeeds, we'll fill the upid below.
422   auto it_and_ins = pids_.Insert(pid, UniquePid{0});
423   if (!it_and_ins.second) {
424     // Ensure that the process has not ended.
425     PERFETTO_DCHECK(!process_table->end_ts()[*it_and_ins.first].has_value());
426     return *it_and_ins.first;
427   }
428 
429   tables::ProcessTable::Row row;
430   row.pid = pid;
431   row.machine_id = context_->machine_id();
432 
433   UniquePid upid = process_table->Insert(row).row;
434   *it_and_ins.first = upid;  // Update the newly inserted hashmap entry.
435 
436   // Create an entry for the main thread.
437   // We cannot call StartNewThread() here, because threads for this process
438   // (including the main thread) might have been seen already prior to this
439   // call. This call usually comes from the ProcessTree dump which is delayed.
440   UpdateThread(/*tid=*/pid, pid);
441   return upid;
442 }
443 
AssociateThreads(UniqueTid utid1,UniqueTid utid2)444 void ProcessTracker::AssociateThreads(UniqueTid utid1, UniqueTid utid2) {
445   auto* tt = context_->storage->mutable_thread_table();
446 
447   // First of all check if one of the two threads is already bound to a process.
448   // If that is the case, map the other thread to the same process and resolve
449   // recursively any associations pending on the other thread.
450 
451   auto opt_upid1 = tt->upid()[utid1];
452   auto opt_upid2 = tt->upid()[utid2];
453 
454   if (opt_upid1.has_value() && !opt_upid2.has_value()) {
455     AssociateThreadToProcess(utid2, *opt_upid1);
456     ResolvePendingAssociations(utid2, *opt_upid1);
457     return;
458   }
459 
460   if (opt_upid2.has_value() && !opt_upid1.has_value()) {
461     AssociateThreadToProcess(utid1, *opt_upid2);
462     ResolvePendingAssociations(utid1, *opt_upid2);
463     return;
464   }
465 
466   if (opt_upid1.has_value() && opt_upid1 != opt_upid2) {
467     // Cannot associate two threads that belong to two different processes.
468     PERFETTO_ELOG("Process tracker failure. Cannot associate threads %u, %u",
469                   tt->tid()[utid1], tt->tid()[utid2]);
470     context_->storage->IncrementStats(stats::process_tracker_errors);
471     return;
472   }
473 
474   pending_assocs_.emplace_back(utid1, utid2);
475 }
476 
ResolvePendingAssociations(UniqueTid utid_arg,UniquePid upid)477 void ProcessTracker::ResolvePendingAssociations(UniqueTid utid_arg,
478                                                 UniquePid upid) {
479   auto* tt = context_->storage->mutable_thread_table();
480   auto* pt = context_->storage->mutable_process_table();
481   PERFETTO_DCHECK(tt->upid()[utid_arg] == upid);
482 
483   std::vector<UniqueTid> resolved_utids;
484   resolved_utids.emplace_back(utid_arg);
485 
486   while (!resolved_utids.empty()) {
487     UniqueTid utid = resolved_utids.back();
488     resolved_utids.pop_back();
489     for (auto it = pending_parent_assocs_.begin();
490          it != pending_parent_assocs_.end();) {
491       UniqueTid parent_utid = it->first;
492       UniquePid child_upid = it->second;
493 
494       if (parent_utid != utid) {
495         ++it;
496         continue;
497       }
498       PERFETTO_DCHECK(child_upid != upid);
499 
500       // Set the parent pid of the other process
501       PERFETTO_DCHECK(!pt->parent_upid()[child_upid] ||
502                       pt->parent_upid()[child_upid] == upid);
503       pt->mutable_parent_upid()->Set(child_upid, upid);
504 
505       // Erase the pair. The |pending_parent_assocs_| vector is not sorted and
506       // swapping a std::pair<uint32_t, uint32_t> is cheap.
507       std::swap(*it, pending_parent_assocs_.back());
508       pending_parent_assocs_.pop_back();
509     }
510 
511     auto end = pending_assocs_.end();
512     for (auto it = pending_assocs_.begin(); it != end;) {
513       UniqueTid other_utid;
514       if (it->first == utid) {
515         other_utid = it->second;
516       } else if (it->second == utid) {
517         other_utid = it->first;
518       } else {
519         ++it;
520         continue;
521       }
522 
523       PERFETTO_DCHECK(other_utid != utid);
524 
525       // Update the other thread and associated it to the same process.
526       PERFETTO_DCHECK(!tt->upid()[other_utid] ||
527                       tt->upid()[other_utid] == upid);
528       AssociateThreadToProcess(other_utid, upid);
529 
530       // Swap the current element to the end of the list and move the end
531       // iterator back. This works because |pending_assocs_| is not sorted. We
532       // do it this way rather than modifying |pending_assocs_| directly to
533       // prevent undefined behaviour caused by modifying a vector while
534       // iterating through it.
535       std::swap(*it, *(--end));
536 
537       // Recurse into the newly resolved thread. Some other threads might have
538       // been bound to that.
539       resolved_utids.emplace_back(other_utid);
540     }
541 
542     // Make sure to actually erase the utids which have been resolved.
543     pending_assocs_.erase(end, pending_assocs_.end());
544   }  // while (!resolved_utids.empty())
545 }
546 
AssociateThreadToProcess(UniqueTid utid,UniquePid upid)547 void ProcessTracker::AssociateThreadToProcess(UniqueTid utid, UniquePid upid) {
548   auto* thread_table = context_->storage->mutable_thread_table();
549   thread_table->mutable_upid()->Set(utid, upid);
550   auto* process_table = context_->storage->mutable_process_table();
551   bool main_thread = thread_table->tid()[utid] == process_table->pid()[upid];
552   thread_table->mutable_is_main_thread()->Set(utid, main_thread);
553 }
554 
SetPidZeroIsUpidZeroIdleProcess()555 void ProcessTracker::SetPidZeroIsUpidZeroIdleProcess() {
556   // Create a mapping from (t|p)id 0 -> u(t|p)id for the idle process.
557   tids_.Insert(0, std::vector<UniqueTid>{swapper_utid_});
558   pids_.Insert(0, swapper_upid_);
559 
560   auto swapper_id = context_->storage->InternString("swapper");
561   UpdateThreadName(0, swapper_id, ThreadNamePriority::kTraceProcessorConstant);
562 }
563 
AddArgsTo(UniquePid upid)564 ArgsTracker::BoundInserter ProcessTracker::AddArgsTo(UniquePid upid) {
565   return args_tracker_.AddArgsTo(upid);
566 }
567 
NotifyEndOfFile()568 void ProcessTracker::NotifyEndOfFile() {
569   args_tracker_.Flush();
570   tids_.Clear();
571   pids_.Clear();
572   pending_assocs_.clear();
573   pending_parent_assocs_.clear();
574   thread_name_priorities_.clear();
575   trusted_pids_.clear();
576   namespaced_threads_.clear();
577   namespaced_processes_.clear();
578 }
579 
UpdateNamespacedProcess(uint32_t pid,std::vector<uint32_t> nspid)580 void ProcessTracker::UpdateNamespacedProcess(uint32_t pid,
581                                              std::vector<uint32_t> nspid) {
582   namespaced_processes_[pid] = {pid, std::move(nspid), {}};
583 }
584 
UpdateNamespacedThread(uint32_t pid,uint32_t tid,std::vector<uint32_t> nstid)585 void ProcessTracker::UpdateNamespacedThread(uint32_t pid,
586                                             uint32_t tid,
587                                             std::vector<uint32_t> nstid) {
588   PERFETTO_DCHECK(namespaced_processes_.find(pid) !=
589                   namespaced_processes_.end());
590   auto& process = namespaced_processes_[pid];
591   process.threads.emplace(tid);
592 
593   namespaced_threads_[tid] = {pid, tid, std::move(nstid)};
594 }
595 
596 }  // namespace perfetto::trace_processor
597