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 "perfetto/base/compiler.h"
19 #include "perfetto/ext/base/string_utils.h"
20 #include "src/trace_processor/importers/common/flow_tracker.h"
21 #include "src/trace_processor/importers/common/process_tracker.h"
22 #include "src/trace_processor/importers/common/slice_tracker.h"
23 #include "src/trace_processor/importers/common/track_tracker.h"
24 #include "src/trace_processor/storage/trace_storage.h"
25 #include "src/trace_processor/types/trace_processor_context.h"
26
27 namespace perfetto {
28 namespace trace_processor {
29
30 namespace {
31 constexpr int kOneWay = 0x01;
32 constexpr int kRootObject = 0x04;
33 constexpr int kStatusCode = 0x08;
34 constexpr int kAcceptFds = 0x10;
35 constexpr int kNoFlags = 0;
36
BinderFlagsToHuman(uint32_t flag)37 std::string BinderFlagsToHuman(uint32_t flag) {
38 std::string str;
39 if (flag & kOneWay) {
40 str += "this is a one-way call: async, no return; ";
41 }
42 if (flag & kRootObject) {
43 str += "contents are the components root object; ";
44 }
45 if (flag & kStatusCode) {
46 str += "contents are a 32-bit status code; ";
47 }
48 if (flag & kAcceptFds) {
49 str += "allow replies with file descriptors; ";
50 }
51 if (flag == kNoFlags) {
52 str += "No Flags Set";
53 }
54 return str;
55 }
56
57 } // namespace
58
BinderTracker(TraceProcessorContext * context)59 BinderTracker::BinderTracker(TraceProcessorContext* context)
60 : context_(context),
61 binder_category_id_(context->storage->InternString("binder")),
62 lock_waiting_id_(context->storage->InternString("binder lock waiting")),
63 lock_held_id_(context->storage->InternString("binder lock held")),
64 transaction_slice_id_(
65 context->storage->InternString("binder transaction")),
66 transaction_async_id_(
67 context->storage->InternString("binder transaction async")),
68 reply_id_(context->storage->InternString("binder reply")),
69 async_rcv_id_(context->storage->InternString("binder async rcv")),
70 transaction_id_(context->storage->InternString("transaction id")),
71 dest_node_(context->storage->InternString("destination node")),
72 dest_process_(context->storage->InternString("destination process")),
73 dest_thread_(context->storage->InternString("destination thread")),
74 dest_name_(context->storage->InternString("destination name")),
75 is_reply_(context->storage->InternString("reply transaction?")),
76 flags_(context->storage->InternString("flags")),
77 code_(context->storage->InternString("code")),
78 calling_tid_(context->storage->InternString("calling tid")),
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,uint32_t dest_tgid,uint32_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 uint32_t dest_tgid,
89 uint32_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 };
110
111 bool is_oneway = (flags & kOneWay) == kOneWay;
112 auto insert_slice = [&]() {
113 if (is_reply) {
114 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
115 static_cast<uint32_t>(dest_tid));
116 auto dest_thread_name = context_->storage->thread_table().name()[utid];
117 auto dest_args_inserter = [this, dest_tid, &dest_thread_name](
118 ArgsTracker::BoundInserter* inserter) {
119 inserter->AddArg(dest_thread_, Variadic::Integer(dest_tid));
120 if (dest_thread_name.has_value()) {
121 inserter->AddArg(dest_name_, Variadic::String(*dest_thread_name));
122 }
123 };
124 context_->slice_tracker->AddArgs(track_id, binder_category_id_, reply_id_,
125 dest_args_inserter);
126 return context_->slice_tracker->End(ts, track_id, kNullStringId,
127 kNullStringId, args_inserter);
128 }
129 if (is_oneway) {
130 return context_->slice_tracker->Scoped(ts, track_id, binder_category_id_,
131 transaction_async_id_, 0,
132 args_inserter);
133 }
134 return context_->slice_tracker->Begin(ts, track_id, binder_category_id_,
135 transaction_slice_id_, args_inserter);
136 };
137
138 OutstandingTransaction transaction;
139 transaction.is_reply = is_reply;
140 transaction.is_oneway = is_oneway;
141 transaction.args_inserter = args_inserter;
142 transaction.send_track_id = track_id;
143 transaction.send_slice_id = insert_slice();
144 outstanding_transactions_.Insert(transaction_id, std::move(transaction));
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 const OutstandingTransaction* opt_transaction =
151 outstanding_transactions_.Find(transaction_id);
152 if (!opt_transaction) {
153 // If we don't know what type of transaction it is, we don't know how to
154 // insert the slice.
155 // TODO(lalitm): maybe we should insert a dummy slice anyway - seems like
156 // a questionable idea to just ignore these completely.
157 return;
158 }
159
160 OutstandingTransaction transaction(std::move(*opt_transaction));
161 outstanding_transactions_.Erase(transaction_id);
162
163 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
164 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
165
166 if (transaction.is_reply) {
167 // Simply end the slice started back when the first |expects_reply|
168 // transaction was sent.
169 context_->slice_tracker->End(ts, track_id);
170 return;
171 }
172
173 base::Optional<SliceId> recv_slice_id;
174 if (transaction.is_oneway) {
175 recv_slice_id = context_->slice_tracker->Scoped(
176 ts, track_id, binder_category_id_, async_rcv_id_, 0,
177 std::move(transaction.args_inserter));
178 } else {
179 if (transaction.send_track_id) {
180 auto args_inserter = [this, utid,
181 pid](ArgsTracker::BoundInserter* inserter) {
182 inserter->AddArg(dest_thread_, Variadic::UnsignedInteger(pid));
183 auto dest_thread_name = context_->storage->thread_table().name()[utid];
184 if (dest_thread_name.has_value()) {
185 inserter->AddArg(dest_name_, Variadic::String(*dest_thread_name));
186 }
187 };
188 context_->slice_tracker->AddArgs(*transaction.send_track_id,
189 binder_category_id_,
190 transaction_slice_id_, args_inserter);
191 }
192 recv_slice_id = context_->slice_tracker->Begin(
193 ts, track_id, binder_category_id_, reply_id_);
194 }
195
196 // Create a flow between the sending slice and this slice.
197 if (transaction.send_slice_id && recv_slice_id) {
198 context_->flow_tracker->InsertFlow(*transaction.send_slice_id,
199 *recv_slice_id);
200 }
201 }
202
Lock(int64_t ts,uint32_t pid)203 void BinderTracker::Lock(int64_t ts, uint32_t pid) {
204 attempt_lock_[pid] = ts;
205
206 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
207 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
208 context_->slice_tracker->Begin(ts, track_id, binder_category_id_,
209 lock_waiting_id_);
210 }
211
Locked(int64_t ts,uint32_t pid)212 void BinderTracker::Locked(int64_t ts, uint32_t pid) {
213 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
214
215 if (!attempt_lock_.Find(pid))
216 return;
217
218 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
219 context_->slice_tracker->End(ts, track_id);
220 context_->slice_tracker->Begin(ts, track_id, binder_category_id_,
221 lock_held_id_);
222
223 lock_acquired_[pid] = ts;
224 attempt_lock_.Erase(pid);
225 }
226
Unlock(int64_t ts,uint32_t pid)227 void BinderTracker::Unlock(int64_t ts, uint32_t pid) {
228 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
229
230 if (!lock_acquired_.Find(pid))
231 return;
232
233 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
234 context_->slice_tracker->End(ts, track_id, binder_category_id_,
235 lock_held_id_);
236 lock_acquired_.Erase(pid);
237 }
238
TransactionAllocBuf(int64_t ts,uint32_t pid,uint64_t data_size,uint64_t offsets_size)239 void BinderTracker::TransactionAllocBuf(int64_t ts,
240 uint32_t pid,
241 uint64_t data_size,
242 uint64_t offsets_size) {
243 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
244 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
245
246 auto args_inserter = [this, &data_size,
247 offsets_size](ArgsTracker::BoundInserter* inserter) {
248 inserter->AddArg(data_size_, Variadic::UnsignedInteger(data_size));
249 inserter->AddArg(offsets_size_, Variadic::UnsignedInteger(offsets_size));
250 };
251 context_->slice_tracker->AddArgs(track_id, binder_category_id_,
252 transaction_slice_id_, args_inserter);
253
254 base::ignore_result(ts);
255 }
256
257 } // namespace trace_processor
258 } // namespace perfetto
259