1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "binder_filter.h"
16 #include "measure_filter.h"
17 #include "process_filter.h"
18 #include "slice_filter.h"
19 #include "stat_filter.h"
20 #include "string_to_numerical.h"
21 namespace SysTuning {
22 namespace TraceStreamer {
BinderFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)23 BinderFilter::BinderFilter(TraceDataCache *dataCache, const TraceStreamerFilters *filter)
24 : FilterBase(dataCache, filter)
25 {
26 binderFlagDescs_ = {{noReturnMsgFlag_, " this is a one-way call: async, no return; "},
27 {rootObjectMsgFlag_, " contents are the components root object; "},
28 {statusCodeMsgFlag_, " contents are a 32-bit status code; "},
29 {acceptFdsMsgFlag_, " allow replies with file descriptors; "},
30 {noFlagsMsgFlag_, " No Flags Set"}};
31 }
32 BinderFilter::~BinderFilter() = default;
33
GetBinderFlagsDesc(uint32_t flag)34 std::string BinderFilter::GetBinderFlagsDesc(uint32_t flag)
35 {
36 std::string str;
37 if (flag & noReturnMsgFlag_) {
38 str += binderFlagDescs_.at(noReturnMsgFlag_);
39 }
40 if (flag & rootObjectMsgFlag_) {
41 str += binderFlagDescs_.at(rootObjectMsgFlag_);
42 }
43 if (flag & statusCodeMsgFlag_) {
44 str += binderFlagDescs_.at(statusCodeMsgFlag_);
45 }
46 if (flag & acceptFdsMsgFlag_) {
47 str += binderFlagDescs_.at(acceptFdsMsgFlag_);
48 }
49 if (flag == noFlagsMsgFlag_) {
50 str += binderFlagDescs_.at(noFlagsMsgFlag_);
51 }
52 return str;
53 }
SendTraction(int64_t ts,uint32_t tid,uint64_t transactionId,int32_t destNode,int32_t destTgid,int32_t destTid,bool isReply,int32_t flags,int32_t code)54 void BinderFilter::SendTraction(int64_t ts,
55 uint32_t tid,
56 uint64_t transactionId,
57 int32_t destNode,
58 int32_t destTgid,
59 int32_t destTid,
60 bool isReply,
61 int32_t flags,
62 int32_t code)
63 {
64 auto flagsStr = traceDataCache_->GetDataIndex("0x" + base::number(flags, base::INTEGER_RADIX_TYPE_HEX) +
65 GetBinderFlagsDesc(flags));
66 DataIndex codeStr = traceDataCache_->GetDataIndex("0x" + base::number(code, base::INTEGER_RADIX_TYPE_HEX) +
67 " Java Layer Dependent");
68 ArgsSet argsSend;
69 argsSend.AppendArg(transId_, BASE_DATA_TYPE_INT, transactionId);
70 argsSend.AppendArg(destNodeId_, BASE_DATA_TYPE_INT, destNode);
71 argsSend.AppendArg(destProcessId_, BASE_DATA_TYPE_INT, destTgid);
72 argsSend.AppendArg(isReplayId_, BASE_DATA_TYPE_BOOLEAN, isReply);
73 argsSend.AppendArg(flagsId_, BASE_DATA_TYPE_STRING, flagsStr);
74 argsSend.AppendArg(codeId_, BASE_DATA_TYPE_STRING, codeStr);
75 argsSend.AppendArg(callingTid_, BASE_DATA_TYPE_INT, tid);
76
77 if (isReply) {
78 // sometime a reply-binder from a tid appear repeated to different dest, we only chose the right one
79 if (transReplyFilter_.count(tid) && transReplyFilter_[tid] == destTid) {
80 // Add dest information to Reply slices, the Begin msg is from TAG-2
81 InternalTid dstItid = streamFilters_->processFilter_->UpdateOrCreateThread(ts, destTid);
82 const auto destThreadName = traceDataCache_->GetConstThreadData(dstItid).nameIndex_;
83 ArgsSet destArgs;
84 destArgs.AppendArg(destThreadId_, BASE_DATA_TYPE_INT, destTid);
85 destArgs.AppendArg(destThreadNameId_, BASE_DATA_TYPE_STRING, destThreadName);
86 (void)streamFilters_->sliceFilter_->AddArgs(tid, binderCatalogId_, replyId_, destArgs);
87 transReplyFilter_.erase(tid);
88 }
89 // the flowing code should be under the ubove conditions, but this will bring a big impact to the UI-SHOW
90 (void)streamFilters_->sliceFilter_->EndBinder(ts, tid, INVALID_UINT64, INVALID_UINT64, argsSend);
91 transReplyWaitingReply_.insert(transactionId);
92 return;
93 } else {
94 bool needReply = !isReply && !(flags & noReturnMsgFlag_);
95 if (needReply) {
96 // transaction needs reply TAG-1
97 (void)streamFilters_->sliceFilter_->BeginBinder(ts, tid, binderCatalogId_, transSliceId_, argsSend);
98 transNeedReply_[transactionId] = tid;
99 } else {
100 // transaction do not need reply
101 // tid calling id
102 // a binder event only care the transactionId and the callint tid
103 (void)streamFilters_->sliceFilter_->AsyncBinder(ts, tid, binderCatalogId_, transAsyncId_, argsSend);
104 asyncBinderEvents_[transactionId] = argsSend;
105 }
106 }
107 }
ReceiveTraction(int64_t ts,uint32_t pid,uint64_t transactionId)108 void BinderFilter::ReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId)
109 {
110 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(ts, pid);
111 const auto threadName = traceDataCache_->GetConstThreadData(internalTid).nameIndex_;
112 if (transReplyWaitingReply_.count(transactionId)) {
113 (void)streamFilters_->sliceFilter_->EndBinder(ts, pid);
114 transReplyWaitingReply_.erase(transactionId);
115 return;
116 }
117
118 if (transNeedReply_.count(transactionId)) {
119 // First, begin the reply, the reply will be end in "SendTraction" func, and the isReply will be true, TAG-2
120 auto replySliceid = streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, replyId_);
121 transReplyFilter_[pid] = transNeedReply_[transactionId];
122 // Add dest info to the reply
123 ArgsSet args;
124 args.AppendArg(destThreadId_, BASE_DATA_TYPE_INT, pid);
125 args.AppendArg(destThreadNameId_, BASE_DATA_TYPE_STRING, threadName);
126 if (IsValidUint32(static_cast<uint32_t>(replySliceid))) {
127 args.AppendArg(destSliceId_, BASE_DATA_TYPE_INT, replySliceid);
128 } else {
129 TS_LOGD("ReceiveTraction, replySliceid value is INVALID!");
130 return;
131 }
132 // Add dest args
133 uint64_t transSliceId = INVALID_UINT32;
134 uint32_t argSetId = INVALID_UINT32;
135 std::tie(transSliceId, argSetId) = streamFilters_->sliceFilter_->AddArgs(transNeedReply_[transactionId],
136 binderCatalogId_, transSliceId_, args);
137
138 // remeber dest slice-id to the argset from "SendTraction" TAG-1
139 ArgsSet replyDestInserter;
140 if (IsValidUint32(transSliceId)) {
141 replyDestInserter.AppendArg(destSliceId_, BASE_DATA_TYPE_INT, transSliceId);
142 } else {
143 TS_LOGD("ReceiveTraction, transSliceId value is INVALID!");
144 return;
145 }
146 std::tie(transSliceId, argSetId) =
147 streamFilters_->sliceFilter_->AddArgs(pid, binderCatalogId_, replyId_, replyDestInserter);
148 traceDataCache_->GetInternalSlicesData()->SetArgSetId(transSliceId, argSetId);
149 transNeedReply_.erase(transactionId);
150 return;
151 }
152 // the code below can be hard to understand, may be a EndBinder will be better
153 // this problem can be test after the IDE is finished
154 if (asyncBinderEvents_.count(transactionId)) {
155 auto args = asyncBinderEvents_[transactionId];
156 (void)streamFilters_->sliceFilter_->AsyncBinder(ts, pid, binderCatalogId_, asyncRcvId_, args);
157 // maybe you can use the flowing code: streamFilters_->sliceFilter_->EndBinder(ts, pid);
158 asyncBinderEvents_.erase(transactionId);
159 return;
160 }
161 }
TransactionAllocBuf(int64_t ts,uint32_t pid,uint64_t dataSize,uint64_t offsetsSize)162 void BinderFilter::TransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize)
163 {
164 ArgsSet args;
165 args.AppendArg(dataSizeId_, BASE_DATA_TYPE_INT, dataSize);
166 args.AppendArg(dataOffsetSizeId_, BASE_DATA_TYPE_INT, offsetsSize);
167 (void)streamFilters_->sliceFilter_->AddArgs(pid, binderCatalogId_, transSliceId_, args);
168 Unused(ts);
169 }
TractionLock(int64_t ts,uint32_t pid,const std::string & tag)170 void BinderFilter::TractionLock(int64_t ts, uint32_t pid, const std::string &tag)
171 {
172 Unused(tag);
173 lastEventTs_[pid] = ts;
174 (void)streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, lockTryId_);
175 }
TractionLocked(int64_t ts,uint32_t pid,const std::string & tag)176 void BinderFilter::TractionLocked(int64_t ts, uint32_t pid, const std::string &tag)
177 {
178 Unused(tag);
179 if (!lastEventTs_.count(pid)) {
180 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, STAT_EVENT_NOTMATCH);
181 return;
182 }
183 (void)streamFilters_->sliceFilter_->EndBinder(ts, pid);
184 (void)streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, lockHoldId_);
185 lastEventTs_.erase(pid);
186 lastEventTs_[pid] = ts;
187 }
TractionUnlock(int64_t ts,uint32_t pid,const std::string & tag)188 void BinderFilter::TractionUnlock(int64_t ts, uint32_t pid, const std::string &tag)
189 {
190 Unused(tag);
191 if (!lastEventTs_.count(pid)) {
192 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, STAT_EVENT_NOTMATCH);
193 return;
194 }
195 (void)streamFilters_->sliceFilter_->EndBinder(ts, pid, binderCatalogId_, lockHoldId_);
196 lastEventTs_.erase(pid);
197 lastEventTs_[pid] = ts;
198 }
IsAsync(int32_t flags) const199 bool BinderFilter::IsAsync(int32_t flags) const
200 {
201 return (flags & noReturnMsgFlag_) == noReturnMsgFlag_;
202 }
Clear()203 void BinderFilter::Clear()
204 {
205 lastEventTs_.clear();
206 transReplyWaitingReply_.clear();
207 transNeedReply_.clear();
208 asyncBinderEvents_.clear();
209 }
210 } // namespace TraceStreamer
211 } // namespace SysTuning
212