• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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