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