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