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