1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
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
16 #include "ipc_payload_statistics_impl.h"
17
18 #include "ipc_debug.h"
19 #include "iremote_object.h"
20 #include "log_tags.h"
21 #include "string_ex.h"
22
23 namespace OHOS {
24 using namespace OHOS::HiviewDFX;
25 static constexpr HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC_PAYLOAD_STATISTICS_IMPL, "IPCPayloadStatisticsImpl"};
26
IPCPayloadStatisticsImpl()27 IPCPayloadStatisticsImpl::IPCPayloadStatisticsImpl() : isStatisticsFlag_(false)
28 {
29 }
30
~IPCPayloadStatisticsImpl()31 IPCPayloadStatisticsImpl::~IPCPayloadStatisticsImpl()
32 {
33 std::unique_lock<std::shared_mutex> lockGuard(dataMutex_);
34 payloadStat_.clear();
35 }
36
GetInstance()37 IPCPayloadStatisticsImpl& IPCPayloadStatisticsImpl::GetInstance()
38 {
39 static IPCPayloadStatisticsImpl instance;
40 return instance;
41 }
42
GetTotalCount()43 uint64_t IPCPayloadStatisticsImpl::GetTotalCount()
44 {
45 uint64_t totalCount = 0;
46
47 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
48 for (auto iterPid = payloadStat_.begin(); iterPid != payloadStat_.end(); ++iterPid) {
49 auto &mapTmp = iterPid->second;
50 for (auto iterDesc = mapTmp.begin(); iterDesc != mapTmp.end(); ++iterDesc) {
51 totalCount += iterDesc->second.count;
52 }
53 }
54 if (totalCount == 0) {
55 ZLOGD(LOG_LABEL, "Statistics may not be enabled.");
56 }
57
58 return totalCount;
59 }
60
GetTotalCost()61 uint64_t IPCPayloadStatisticsImpl::GetTotalCost()
62 {
63 uint64_t totalCost = 0;
64
65 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
66 for (auto iterPid = payloadStat_.begin(); iterPid != payloadStat_.end(); ++iterPid) {
67 auto &mapTmp = iterPid->second;
68 for (auto iterDesc = mapTmp.begin(); iterDesc != mapTmp.end(); ++iterDesc) {
69 totalCost += iterDesc->second.cost.totalCost;
70 }
71 }
72 if (totalCost == 0) {
73 ZLOGD(LOG_LABEL, "Statistics may not be enabled.");
74 }
75
76 return totalCost;
77 }
78
GetPids()79 std::vector<int32_t> IPCPayloadStatisticsImpl::GetPids()
80 {
81 std::vector<int32_t> vec;
82
83 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
84 for (auto iterPid = payloadStat_.begin(); iterPid != payloadStat_.end(); ++iterPid) {
85 vec.emplace_back(iterPid->first);
86 }
87 if (vec.size() == 0) {
88 ZLOGD(LOG_LABEL, "Statistics may not be enabled.");
89 }
90
91 return vec;
92 }
93
GetCount(const int32_t pid)94 uint64_t IPCPayloadStatisticsImpl::GetCount(const int32_t pid)
95 {
96 uint64_t count = 0;
97
98 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
99 auto iterPid = payloadStat_.find(pid);
100 if (iterPid != payloadStat_.end()) {
101 auto &mapTmp = iterPid->second;
102 for (auto iterDesc = mapTmp.begin(); iterDesc != mapTmp.end(); ++iterDesc) {
103 count += iterDesc->second.count;
104 }
105 } else {
106 ZLOGD(LOG_LABEL, "There is no data corresponding to the current PID.");
107 }
108
109 return count;
110 }
111
GetCost(const int32_t pid)112 uint64_t IPCPayloadStatisticsImpl::GetCost(const int32_t pid)
113 {
114 uint64_t cost = 0;
115
116 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
117 auto iterPid = payloadStat_.find(pid);
118 if (iterPid != payloadStat_.end()) {
119 auto &mapTmp = iterPid->second;
120 for (auto iterDesc = mapTmp.begin(); iterDesc != mapTmp.end(); ++iterDesc) {
121 cost += iterDesc->second.cost.totalCost;
122 }
123 } else {
124 ZLOGD(LOG_LABEL, "There is no data corresponding to the current PID.");
125 }
126
127 return cost;
128 }
129
GetDescriptorCodes(const int32_t pid)130 std::vector<IPCInterfaceInfo> IPCPayloadStatisticsImpl::GetDescriptorCodes(const int32_t pid)
131 {
132 std::vector<IPCInterfaceInfo> vec;
133 IPCInterfaceInfo info;
134
135 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
136 auto iterPid = payloadStat_.find(pid);
137 if (iterPid == payloadStat_.end()) {
138 ZLOGD(LOG_LABEL, "There is no data corresponding to the current PID.");
139 return vec;
140 }
141 auto &mapTmp = iterPid->second;
142 for (auto iterDesc = mapTmp.begin(); iterDesc != mapTmp.end(); ++iterDesc) {
143 vec.emplace_back(iterDesc->second.interface);
144 }
145
146 return vec;
147 }
148
GetDescriptorCodeCount(const int32_t pid,const std::u16string & desc,const int32_t code)149 uint64_t IPCPayloadStatisticsImpl::GetDescriptorCodeCount(
150 const int32_t pid, const std::u16string &desc, const int32_t code)
151 {
152 IPCPayloadInfo payloadInfo = {{u"", 0}, {0, 0, 0, 0}, 0};
153
154 bool ret = GetPayloadInfo(pid, desc, code, payloadInfo);
155 if (!ret) {
156 ZLOGD(LOG_LABEL, "Failed to obtain the total number of count.");
157 }
158 return payloadInfo.count;
159 }
160
GetDescriptorCodeCost(const int32_t pid,const std::u16string & desc,const int32_t code)161 IPCPayloadCost IPCPayloadStatisticsImpl::GetDescriptorCodeCost(
162 const int32_t pid, const std::u16string &desc, const int32_t code)
163 {
164 IPCPayloadInfo payloadInfo = {{u"", 0}, {0, 0, 0, 0}, 0};
165 IPCPayloadCost cost = { 0, 0, 0, 0 };
166
167 bool ret = GetPayloadInfo(pid, desc, code, payloadInfo);
168 if (!ret) {
169 ZLOGD(LOG_LABEL, "Failed to obtain IPCPayloadCost.");
170 return cost;
171 }
172 if (payloadInfo.count == 0) {
173 ZLOGD(LOG_LABEL, "Divisor cannot be 0.");
174 return cost;
175 }
176
177 payloadInfo.cost.averCost = payloadInfo.cost.totalCost / payloadInfo.count;
178 return payloadInfo.cost;
179 }
180
GetPayloadInfo(const int32_t pid,const std::u16string & desc,const int32_t code,IPCPayloadInfo & payloadInfo)181 bool IPCPayloadStatisticsImpl::GetPayloadInfo(
182 const int32_t pid, const std::u16string &desc, const int32_t code, IPCPayloadInfo &payloadInfo)
183 {
184 bool ret = false;
185
186 std::shared_lock<std::shared_mutex> lockGuard(dataMutex_);
187 auto iterPid = payloadStat_.find(pid);
188 if (iterPid == payloadStat_.end()) {
189 ZLOGD(LOG_LABEL, "There is no data corresponding to the current PID.");
190 return ret;
191 }
192
193 auto &mapTmp = iterPid->second;
194 for (auto iterDesc = mapTmp.begin(); iterDesc != mapTmp.end(); ++iterDesc) {
195 if ((code == iterDesc->second.interface.code) && (desc == iterDesc->second.interface.desc)) {
196 payloadInfo = iterDesc->second;
197 ret = true;
198 break;
199 }
200 }
201 if (!ret) {
202 ZLOGD(LOG_LABEL, "There is no corresponding descriptor and code in the current process.");
203 }
204 return ret;
205 }
206
StartStatistics()207 bool IPCPayloadStatisticsImpl::StartStatistics()
208 {
209 if (!isStatisticsFlag_) {
210 std::unique_lock<std::shared_mutex> lockGuard(dataMutex_);
211 payloadStat_.clear();
212 } else {
213 ZLOGD(LOG_LABEL, "Statistics have started, no need to start again.");
214 return true;
215 }
216
217 isStatisticsFlag_ = true;
218 return true;
219 }
220
StopStatistics()221 bool IPCPayloadStatisticsImpl::StopStatistics()
222 {
223 if (!isStatisticsFlag_) {
224 ZLOGD(LOG_LABEL, "Statistics have been stopped, no need to stop again.");
225 return true;
226 }
227
228 isStatisticsFlag_ = false;
229 return true;
230 }
231
GetStatisticsStatus()232 bool IPCPayloadStatisticsImpl::GetStatisticsStatus()
233 {
234 return isStatisticsFlag_;
235 }
236
ClearStatisticsData()237 bool IPCPayloadStatisticsImpl::ClearStatisticsData()
238 {
239 std::unique_lock<std::shared_mutex> lockGuard(dataMutex_);
240 payloadStat_.clear();
241 return true;
242 }
243
UpdatePayloadInfo(const int32_t pid,const std::u16string & desc,const int32_t code,const uint32_t currentCost)244 bool IPCPayloadStatisticsImpl::UpdatePayloadInfo(
245 const int32_t pid, const std::u16string &desc, const int32_t code, const uint32_t currentCost)
246 {
247 if (currentCost == 0 || !isStatisticsFlag_) {
248 return false;
249 }
250
251 IPCPayloadInfo payloadInfo;
252 std::u16string descTmp = desc;
253 std::u16string descKey = descTmp + u"_" + Str8ToStr16(std::to_string(code));
254
255 payloadInfo.interface.desc = desc;
256 payloadInfo.interface.code = code;
257 payloadInfo.count = 1; // Update the map once and increase the count once.
258 payloadInfo.cost.totalCost = currentCost;
259 payloadInfo.cost.maxCost = currentCost;
260 payloadInfo.cost.minCost = currentCost;
261 payloadInfo.cost.averCost = 0; // To improve performance, the average time consumption is not calculated.
262
263 std::unique_lock<std::shared_mutex> lockGuard(dataMutex_);
264 auto iterPid = payloadStat_.find(pid);
265 if (iterPid == payloadStat_.end()) {
266 std::map<std::u16string, IPCPayloadInfo> temp;
267 temp.insert(std::make_pair(descKey, payloadInfo));
268 payloadStat_.insert(std::make_pair(pid, temp));
269 return true;
270 }
271
272 auto iterDesc = iterPid->second.find(descKey);
273 if (iterDesc == iterPid->second.end()) {
274 iterPid->second.insert(std::make_pair(descKey, payloadInfo));
275 return true;
276 }
277
278 iterDesc->second.count++;
279 iterDesc->second.cost.totalCost += currentCost;
280 if (iterDesc->second.cost.maxCost < currentCost) {
281 iterDesc->second.cost.maxCost = currentCost;
282 }
283 if (iterDesc->second.cost.minCost > currentCost) {
284 iterDesc->second.cost.minCost = currentCost;
285 }
286
287 return true;
288 }
289 } // namespace OHOS
290