1 /*
2 * Copyright (c) 2021 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 #include "flow_control_init.h"
16
17 #include <fstream>
18 #include <iostream>
19 #include <strstream>
20 #include <string>
21 #include <ctime>
22 #include <atomic>
23 #include <unordered_map>
24 #include <unistd.h>
25 #include <hilog/log.h>
26 #include "properties.h"
27 #include "log_time_stamp.h"
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 static const int DOMAIN_FILTER = 0x00fffff;
32 static const int DOMAIN_FILTER_SUBSYSTEM = 8;
33
34 using DomainInfo = struct {
35 std::string domain;
36 uint32_t domainId;
37 uint32_t domainQuota;
38 uint32_t sumLen;
39 uint32_t dropped;
40 LogTimeStamp startTime;
41 };
42
43 static std::unordered_map<uint32_t, DomainInfo*> g_domainMap;
44
45 static int32_t g_typeDropped[LOG_TYPE_MAX];
46 static std::unordered_map<uint32_t, int32_t> g_domainDropped;
47
ClearDroppedByType()48 void ClearDroppedByType()
49 {
50 int i;
51 for (i = 0; i < LOG_TYPE_MAX; i++) {
52 g_typeDropped[i] = 0;
53 }
54 }
55
ClearDroppedByDomain()56 void ClearDroppedByDomain()
57 {
58 std::unordered_map<uint32_t, int32_t>::iterator it;
59 for (it = g_domainDropped.begin(); it != g_domainDropped.end(); ++it) {
60 it->second = 0;
61 }
62 }
63
IncreaseDropped(uint32_t domainId,uint16_t logType)64 void IncreaseDropped(uint32_t domainId, uint16_t logType)
65 {
66 std::unordered_map<uint32_t, int32_t>::iterator it;
67 g_typeDropped[logType]++;
68 it = g_domainDropped.find(domainId);
69 if (it != g_domainDropped.end()) {
70 it->second++;
71 } else {
72 g_domainDropped.insert({ domainId, 1 });
73 }
74 }
75
GetDroppedByType(uint16_t logType)76 int32_t GetDroppedByType(uint16_t logType)
77 {
78 return g_typeDropped[logType];
79 }
80
GetDroppedByDomain(uint32_t domainId)81 int32_t GetDroppedByDomain(uint32_t domainId)
82 {
83 std::unordered_map<uint32_t, int32_t>::iterator it = g_domainDropped.find(domainId);
84 if (it != g_domainDropped.end()) {
85 return it->second;
86 }
87 return 0;
88 }
89
ParseDomainQuota(std::string & domainStr)90 void ParseDomainQuota(std::string &domainStr)
91 {
92 if (domainStr.empty() || domainStr.at(0) == '#') {
93 return;
94 }
95 std::string domainIdStr;
96 std::string domainName;
97 std::string peakStr;
98 std::size_t domainIdEnd = domainStr.find_first_of(" ");
99 if (domainIdEnd == std::string::npos) {
100 return;
101 }
102 domainIdStr = domainStr.substr(0, domainIdEnd);
103 if (++domainIdEnd >= domainStr.size()) {
104 return;
105 }
106 std::size_t domainNameEnd = domainStr.find_first_of(" ", domainIdEnd);
107 if (domainNameEnd == std::string::npos) {
108 return;
109 }
110 domainName = domainStr.substr(domainIdEnd, domainNameEnd - domainIdEnd);
111 if (++domainNameEnd >= domainStr.size()) {
112 return;
113 }
114 peakStr = domainStr.substr(domainNameEnd);
115 uint32_t domain = static_cast<uint32_t>(std::stoi(domainIdStr, nullptr, 0));
116 uint32_t peak = static_cast<uint32_t>(std::stoi(peakStr, nullptr, 0));
117 if (domain <= 0 || peak <= 0) {
118 return;
119 }
120 uint32_t domainId = (domain & DOMAIN_FILTER) >> DOMAIN_FILTER_SUBSYSTEM;
121 // resident resources, no need to write the corresponding delete code
122
123 DomainInfo* domainInfo = static_cast<DomainInfo *>(new DomainInfo);
124 if (domainInfo) {
125 domainInfo->domain = domainName;
126 domainInfo->domainId = domainId;
127 domainInfo->domainQuota = peak;
128 domainInfo->startTime.SetTimeStamp(0, 0);
129 domainInfo->sumLen = 0;
130 domainInfo->dropped = 0;
131 g_domainMap.insert({ domainId, domainInfo });
132 #ifdef DEBUG
133 std::cout << "init domain control, domain:" << domainInfo->domain;
134 std::cout << ", id: " << std::hex << domainId << std::dec;
135 std::cout << ", quota: " << domainInfo->domainQuota << std::endl;
136 #endif
137 }
138 }
139
InitDomainFlowCtrl()140 int32_t InitDomainFlowCtrl()
141 {
142 static constexpr char domainFile[] = "/system/etc/hilog_domains.conf";
143 std::ifstream ifs(domainFile, std::ifstream::in);
144 if (!ifs.is_open()) {
145 #ifdef DEBUG
146 std::cout << "open file failed" << std::endl;
147 #endif
148 return ERR_FLOWCONTROL_CONF_OPEN_FAIL;
149 }
150 std::string line;
151 while (!ifs.eof()) {
152 getline(ifs, line);
153 ParseDomainQuota(line);
154 }
155 ifs.close();
156 ClearDroppedByType();
157 ClearDroppedByDomain();
158 return 0;
159 }
160
FlowCtrlDomain(HilogMsg * hilogMsg)161 int FlowCtrlDomain(HilogMsg* hilogMsg)
162 {
163 if (hilogMsg->type == LOG_APP || !IsDomainSwitchOn() || IsDebugOn()) {
164 return 0;
165 }
166 LogTimeStamp tsNow(0, 0);
167 std::unordered_map<uint32_t, DomainInfo*>::iterator it;
168 uint32_t domain = hilogMsg->domain;
169 uint32_t domainId = (domain & DOMAIN_FILTER) >> DOMAIN_FILTER_SUBSYSTEM;
170 auto logLen = hilogMsg->len - sizeof(HilogMsg) - 1 - 1; /* quota length exclude '\0' of tag and log content */
171 int ret = 0;
172 it = g_domainMap.find(domainId);
173 if (it != g_domainMap.end()) {
174 LogTimeStamp tsNow(CLOCK_MONOTONIC);
175 /* in statistic period(1 second) */
176 if ((tsNow -= it->second->startTime) < LogTimeStamp(1)) {
177 if (it->second->sumLen <= it->second->domainQuota) { /* under quota */
178 it->second->sumLen += logLen;
179 ret = 0;
180 } else { /* over quota */
181 IncreaseDropped(domainId, hilogMsg->type);
182 it->second->dropped++;
183 ret = -1;
184 }
185 } else { /* new statistic period */
186 it->second->startTime = tsNow;
187 it->second->sumLen = logLen;
188 ret = static_cast<int>(it->second->dropped);
189 it->second->dropped = 0;
190 }
191 }
192
193 return ret;
194 }
195 }
196 }
197