1 /*
2  * Copyright (C) 2019 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/ftrace/binder_tracker.h"
18 #include "src/trace_processor/importers/common/process_tracker.h"
19 #include "src/trace_processor/importers/common/slice_tracker.h"
20 #include "src/trace_processor/importers/common/track_tracker.h"
21 #include "src/trace_processor/types/trace_processor_context.h"
22 
23 #include "perfetto/base/compiler.h"
24 #include "perfetto/ext/base/string_utils.h"
25 
26 namespace perfetto {
27 namespace trace_processor {
28 
29 namespace {
30 constexpr int kOneWay = 0x01;
31 constexpr int kRootObject = 0x04;
32 constexpr int kStatusCode = 0x08;
33 constexpr int kAcceptFds = 0x10;
34 constexpr int kNoFlags = 0;
35 
BinderFlagsToHuman(uint32_t flag)36 std::string BinderFlagsToHuman(uint32_t flag) {
37   std::string str;
38   if (flag & kOneWay) {
39     str += "this is a one-way call: async, no return; ";
40   }
41   if (flag & kRootObject) {
42     str += "contents are the components root object; ";
43   }
44   if (flag & kStatusCode) {
45     str += "contents are a 32-bit status code; ";
46   }
47   if (flag & kAcceptFds) {
48     str += "allow replies with file descriptors; ";
49   }
50   if (flag == kNoFlags) {
51     str += "No Flags Set";
52   }
53   return str;
54 }
55 
56 }  // namespace
57 
BinderTracker(TraceProcessorContext * context)58 BinderTracker::BinderTracker(TraceProcessorContext* context)
59     : context_(context),
60       binder_category_id_(context->storage->InternString("binder")),
61       lock_waiting_id_(context->storage->InternString("binder lock waiting")),
62       lock_held_id_(context->storage->InternString("binder lock held")),
63       transaction_slice_id_(
64           context->storage->InternString("binder transaction")),
65       transaction_async_id_(
66           context->storage->InternString("binder transaction async")),
67       reply_id_(context->storage->InternString("binder reply")),
68       async_rcv_id_(context->storage->InternString("binder async rcv")),
69       transaction_id_(context->storage->InternString("transaction id")),
70       dest_node_(context->storage->InternString("destination node")),
71       dest_process_(context->storage->InternString("destination process")),
72       dest_thread_(context->storage->InternString("destination thread")),
73       dest_name_(context->storage->InternString("destination name")),
74       is_reply_(context->storage->InternString("reply transaction?")),
75       flags_(context->storage->InternString("flags")),
76       code_(context->storage->InternString("code")),
77       calling_tid_(context->storage->InternString("calling tid")),
78       dest_slice_id_(context->storage->InternString("destination slice id")),
79       data_size_(context->storage->InternString("data size")),
80       offsets_size_(context->storage->InternString("offsets size")) {}
81 
82 BinderTracker::~BinderTracker() = default;
83 
Transaction(int64_t ts,uint32_t tid,int32_t transaction_id,int32_t dest_node,int32_t dest_tgid,int32_t dest_tid,bool is_reply,uint32_t flags,StringId code)84 void BinderTracker::Transaction(int64_t ts,
85                                 uint32_t tid,
86                                 int32_t transaction_id,
87                                 int32_t dest_node,
88                                 int32_t dest_tgid,
89                                 int32_t dest_tid,
90                                 bool is_reply,
91                                 uint32_t flags,
92                                 StringId code) {
93   UniqueTid src_utid = context_->process_tracker->GetOrCreateThread(tid);
94   TrackId track_id = context_->track_tracker->InternThreadTrack(src_utid);
95 
96   auto args_inserter = [this, transaction_id, dest_node, dest_tgid, is_reply,
97                         flags, code,
98                         tid](ArgsTracker::BoundInserter* inserter) {
99     inserter->AddArg(transaction_id_, Variadic::Integer(transaction_id));
100     inserter->AddArg(dest_node_, Variadic::Integer(dest_node));
101     inserter->AddArg(dest_process_, Variadic::Integer(dest_tgid));
102     inserter->AddArg(is_reply_, Variadic::Boolean(is_reply));
103     std::string flag_str =
104         base::IntToHexString(flags) + " " + BinderFlagsToHuman(flags);
105     inserter->AddArg(flags_, Variadic::String(context_->storage->InternString(
106                                  base::StringView(flag_str))));
107     inserter->AddArg(code_, Variadic::String(code));
108     inserter->AddArg(calling_tid_, Variadic::UnsignedInteger(tid));
109     // TODO(hjd): The legacy UI included the calling pid in the args,
110     // is this necessary? It's complicated in our case because process
111     // association might not happen until after the binder transaction slices
112     // have been parsed. We would need to backfill the arg.
113   };
114 
115   if (is_reply) {
116     // Reply slices have accurate dest information, so we can add it.
117     const auto& thread_table = context_->storage->thread_table();
118     UniqueTid utid = context_->process_tracker->GetOrCreateThread(
119         static_cast<uint32_t>(dest_tid));
120     StringId dest_thread_name = thread_table.name()[utid];
121     auto dest_args_inserter = [this, dest_tid, &dest_thread_name](
122                                   ArgsTracker::BoundInserter* inserter) {
123       inserter->AddArg(dest_thread_, Variadic::Integer(dest_tid));
124       inserter->AddArg(dest_name_, Variadic::String(dest_thread_name));
125     };
126     context_->slice_tracker->AddArgs(track_id, binder_category_id_, reply_id_,
127                                      dest_args_inserter);
128     context_->slice_tracker->End(ts, track_id, kNullStringId, kNullStringId,
129                                  args_inserter);
130     awaiting_rcv_for_reply_.insert(transaction_id);
131     return;
132   }
133 
134   bool expects_reply = !is_reply && ((flags & kOneWay) == 0);
135 
136   if (expects_reply) {
137     context_->slice_tracker->Begin(ts, track_id, binder_category_id_,
138                                    transaction_slice_id_, args_inserter);
139     transaction_await_rcv[transaction_id] = track_id;
140   } else {
141     context_->slice_tracker->Scoped(ts, track_id, binder_category_id_,
142                                     transaction_async_id_, 0, args_inserter);
143     awaiting_async_rcv_[transaction_id] = args_inserter;
144   }
145 }
146 
TransactionReceived(int64_t ts,uint32_t pid,int32_t transaction_id)147 void BinderTracker::TransactionReceived(int64_t ts,
148                                         uint32_t pid,
149                                         int32_t transaction_id) {
150   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
151   const auto& thread_table = context_->storage->thread_table();
152   StringId thread_name = thread_table.name()[utid];
153   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
154   if (awaiting_rcv_for_reply_.count(transaction_id) > 0) {
155     context_->slice_tracker->End(ts, track_id);
156     awaiting_rcv_for_reply_.erase(transaction_id);
157     return;
158   }
159 
160   if (transaction_await_rcv.count(transaction_id) > 0) {
161     // First begin the reply slice to get its slice id.
162     auto reply_slice_id = context_->slice_tracker->Begin(
163         ts, track_id, binder_category_id_, reply_id_);
164     // Add accurate dest info to the binder transaction slice.
165     auto args_inserter = [this, pid, &thread_name, &reply_slice_id](
166                              ArgsTracker::BoundInserter* inserter) {
167       inserter->AddArg(dest_thread_, Variadic::UnsignedInteger(pid));
168       inserter->AddArg(dest_name_, Variadic::String(thread_name));
169       if (reply_slice_id.has_value())
170         inserter->AddArg(dest_slice_id_,
171                          Variadic::UnsignedInteger(reply_slice_id->value));
172     };
173     // Add the dest args to the current transaction slice and get the slice id.
174     auto transaction_slice_id = context_->slice_tracker->AddArgs(
175         transaction_await_rcv[transaction_id], binder_category_id_,
176         transaction_slice_id_, args_inserter);
177 
178     // Add the dest slice id to the reply slice that has just begun.
179     auto reply_dest_inserter =
180         [this, &transaction_slice_id](ArgsTracker::BoundInserter* inserter) {
181           if (transaction_slice_id.has_value())
182             inserter->AddArg(dest_slice_id_, Variadic::UnsignedInteger(
183                                                  transaction_slice_id.value()));
184         };
185     context_->slice_tracker->AddArgs(track_id, binder_category_id_, reply_id_,
186                                      reply_dest_inserter);
187     transaction_await_rcv.erase(transaction_id);
188     return;
189   }
190 
191   if (awaiting_async_rcv_.count(transaction_id) > 0) {
192     auto args = awaiting_async_rcv_[transaction_id];
193     context_->slice_tracker->Scoped(ts, track_id, binder_category_id_,
194                                     async_rcv_id_, 0, args);
195     awaiting_async_rcv_.erase(transaction_id);
196     return;
197   }
198 }
199 
Lock(int64_t ts,uint32_t pid)200 void BinderTracker::Lock(int64_t ts, uint32_t pid) {
201   attempt_lock_[pid] = ts;
202 
203   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
204   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
205   context_->slice_tracker->Begin(ts, track_id, binder_category_id_,
206                                  lock_waiting_id_);
207 }
208 
Locked(int64_t ts,uint32_t pid)209 void BinderTracker::Locked(int64_t ts, uint32_t pid) {
210   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
211 
212   if (attempt_lock_.count(pid) == 0)
213     return;
214 
215   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
216   context_->slice_tracker->End(ts, track_id);
217   context_->slice_tracker->Begin(ts, track_id, binder_category_id_,
218                                  lock_held_id_);
219 
220   lock_acquired_[pid] = ts;
221   attempt_lock_.erase(pid);
222 }
223 
Unlock(int64_t ts,uint32_t pid)224 void BinderTracker::Unlock(int64_t ts, uint32_t pid) {
225   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
226 
227   if (lock_acquired_.count(pid) == 0)
228     return;
229 
230   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
231   context_->slice_tracker->End(ts, track_id, binder_category_id_,
232                                lock_held_id_);
233   lock_acquired_.erase(pid);
234 }
235 
TransactionAllocBuf(int64_t ts,uint32_t pid,uint64_t data_size,uint64_t offsets_size)236 void BinderTracker::TransactionAllocBuf(int64_t ts,
237                                         uint32_t pid,
238                                         uint64_t data_size,
239                                         uint64_t offsets_size) {
240   UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
241   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
242 
243   auto args_inserter = [this, &data_size,
244                         offsets_size](ArgsTracker::BoundInserter* inserter) {
245     inserter->AddArg(data_size_, Variadic::UnsignedInteger(data_size));
246     inserter->AddArg(offsets_size_, Variadic::UnsignedInteger(offsets_size));
247   };
248   context_->slice_tracker->AddArgs(track_id, binder_category_id_,
249                                    transaction_slice_id_, args_inserter);
250 
251   base::ignore_result(ts);
252 }
253 
254 }  // namespace trace_processor
255 }  // namespace perfetto
256