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