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 
16 #include "freeze_detector_plugin.h"
17 
18 #include <algorithm>
19 
20 #include "ffrt.h"
21 #include "hiview_logger.h"
22 #include "plugin_factory.h"
23 #include "process_status.h"
24 #include "string_util.h"
25 #include "sys_event_dao.h"
26 
27 #include "decoded/decoded_event.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 REGISTER_PROXY(FreezeDetectorPlugin);
32 DEFINE_LOG_LABEL(0xD002D01, "FreezeDetector");
FreezeDetectorPlugin()33 FreezeDetectorPlugin::FreezeDetectorPlugin()
34 {
35 }
36 
~FreezeDetectorPlugin()37 FreezeDetectorPlugin::~FreezeDetectorPlugin()
38 {
39 }
40 
ReadyToLoad()41 bool FreezeDetectorPlugin::ReadyToLoad()
42 {
43     freezeCommon_ = std::make_shared<FreezeCommon>();
44     bool ret1 = freezeCommon_->Init();
45     freezeResolver_ = std::make_unique<FreezeResolver>(freezeCommon_);
46     bool ret2 = freezeResolver_->Init();
47     return ret1 && ret2;
48 }
49 
OnLoad()50 void FreezeDetectorPlugin::OnLoad()
51 {
52     HIVIEW_LOGD("OnLoad.");
53     SetName(FREEZE_DETECTOR_PLUGIN_NAME);
54     SetVersion(FREEZE_DETECTOR_PLUGIN_VERSION);
55 
56     freezeCommon_ = std::make_shared<FreezeCommon>();
57     bool ret = freezeCommon_->Init();
58     if (!ret) {
59         HIVIEW_LOGW("freezeCommon_->Init false.");
60         freezeCommon_ = nullptr;
61         return;
62     }
63     freezeResolver_ = std::make_unique<FreezeResolver>(freezeCommon_);
64     ret = freezeResolver_->Init();
65     if (!ret) {
66         HIVIEW_LOGW("freezeResolver_->Init false.");
67         freezeCommon_ = nullptr;
68         freezeResolver_ = nullptr;
69     }
70 }
71 
OnUnload()72 void FreezeDetectorPlugin::OnUnload()
73 {
74     HIVIEW_LOGD("OnUnload.");
75 }
76 
OnEvent(std::shared_ptr<Event> & event)77 bool FreezeDetectorPlugin::OnEvent(std::shared_ptr<Event> &event)
78 {
79     return false;
80 }
81 
CanProcessEvent(std::shared_ptr<Event> event)82 bool FreezeDetectorPlugin::CanProcessEvent(std::shared_ptr<Event> event)
83 {
84     return false;
85 }
86 
RemoveRedundantNewline(const std::string & content) const87 std::string FreezeDetectorPlugin::RemoveRedundantNewline(const std::string& content) const
88 {
89     std::vector<std::string> lines;
90     StringUtil::SplitStr(content, "\\n", lines, false, false);
91 
92     std::string outContent;
93     for (const auto& line : lines) {
94         outContent.append(line).append("\n");
95     }
96     return outContent;
97 }
98 
MakeWatchPoint(const Event & event)99 WatchPoint FreezeDetectorPlugin::MakeWatchPoint(const Event& event)
100 {
101     Event& eventRef = const_cast<Event&>(event);
102     SysEvent& sysEvent = static_cast<SysEvent&>(eventRef);
103 
104     long seq = sysEvent.GetSeq();
105     long tid = sysEvent.GetTid();
106     long pid = sysEvent.GetEventIntValue(FreezeCommon::EVENT_PID);
107     pid = pid ? pid : sysEvent.GetPid();
108     long uid = sysEvent.GetEventIntValue(FreezeCommon::EVENT_UID);
109     uid = uid ? uid : sysEvent.GetUid();
110     std::string packageName = sysEvent.GetEventValue(FreezeCommon::EVENT_PACKAGE_NAME);
111     std::string processName = sysEvent.GetEventValue(FreezeCommon::EVENT_PROCESS_NAME);
112     std::string hiteaceTime = sysEvent.GetEventValue(FreezeCommon::HIREACE_TIME);
113     std::string sysrqTime = sysEvent.GetEventValue(FreezeCommon::SYSRQ_TIME);
114     std::string info = sysEvent.GetEventValue(EventStore::EventCol::INFO);
115     std::regex reg("logPath:([^,]+)");
116     std::smatch result;
117     std::string logPath = "";
118     if (std::regex_search(info, result, reg)) {
119         logPath = result[1].str();
120     } else if (info == "nolog") {
121         logPath = info;
122     }
123     std::string foreGround = "";
124     CheckForeGround(uid, pid, event.happenTime_, foreGround);
125     WatchPoint watchPoint = OHOS::HiviewDFX::WatchPoint::Builder()
126         .InitSeq(seq)
127         .InitDomain(event.domain_)
128         .InitStringId(event.eventName_)
129         .InitTimestamp(event.happenTime_)
130         .InitPid(pid)
131         .InitTid(tid)
132         .InitUid(uid)
133         .InitPackageName(packageName)
134         .InitProcessName(processName)
135         .InitForeGround(foreGround)
136         .InitMsg("")
137         .InitLogPath(logPath)
138         .InitHitraceTime(hiteaceTime)
139         .InitSysrqTime(sysrqTime)
140         .Build();
141     HIVIEW_LOGI("watchpoint domain=%{public}s, stringid=%{public}s, pid=%{public}ld, uid=%{public}ld, seq=%{public}ld,"
142         " packageName=%{public}s, processName=%{public}s, logPath=%{public}s.", event.domain_.c_str(),
143         event.eventName_.c_str(), pid, uid, seq, packageName.c_str(), processName.c_str(), logPath.c_str());
144 
145     return watchPoint;
146 }
147 
CheckForeGround(long uid,long pid,unsigned long long eventTime,std::string & foreGround)148 void FreezeDetectorPlugin::CheckForeGround(long uid, long pid, unsigned long long eventTime, std::string& foreGround)
149 {
150     if (uid < minAppUid) {
151         return;
152     }
153 
154     UCollectUtil::ProcessState state = UCollectUtil::ProcessStatus::GetInstance().GetProcessState(pid);
155     if (state == UCollectUtil::FOREGROUND) {
156         foreGround = "Yes";
157     }
158     if (state == UCollectUtil::BACKGROUND) {
159         uint64_t lastFgTime = static_cast<uint64_t>(UCollectUtil::ProcessStatus::GetInstance()
160             .GetProcessLastForegroundTime(pid));
161         foreGround = (lastFgTime > eventTime) ? "Yes" : "No";
162     }
163 }
164 
OnEventListeningCallback(const Event & event)165 void FreezeDetectorPlugin::OnEventListeningCallback(const Event& event)
166 {
167     if (event.rawData_ == nullptr) {
168         HIVIEW_LOGE("raw data of event is null.");
169         return;
170     }
171     EventRaw::DecodedEvent decodedEvent(event.rawData_->GetData());
172     if (!decodedEvent.IsValid()) {
173         HIVIEW_LOGE("failed to decode the raw data of event.");
174         return;
175     }
176     HIVIEW_LOGD("received event id=%{public}u, domain=%{public}s, stringid=%{public}s, extraInfo=%{public}s.",
177         event.eventId_, event.domain_.c_str(), event.eventName_.c_str(), decodedEvent.AsJsonStr().c_str());
178     if (freezeCommon_ == nullptr) {
179         return;
180     }
181 
182     if (!freezeCommon_->IsFreezeEvent(event.domain_, event.eventName_)) {
183         HIVIEW_LOGE("not freeze event.");
184         return;
185     }
186 
187     HIVIEW_LOGD("received event domain=%{public}s, stringid=%{public}s",
188         event.domain_.c_str(), event.eventName_.c_str());
189     this->AddUseCount();
190     // dispatcher context, send task to our thread
191     WatchPoint watchPoint = MakeWatchPoint(event);
192     if (watchPoint.GetLogPath().empty()) {
193         HIVIEW_LOGW("log path is empty.");
194         return;
195     }
196 
197     std::shared_ptr<FreezeRuleCluster> freezeRuleCluster = freezeCommon_->GetFreezeRuleCluster();
198     std::vector<FreezeResult> freezeResultList;
199     bool ruleRet = freezeRuleCluster->GetResult(watchPoint, freezeResultList);
200     if (!ruleRet) {
201         HIVIEW_LOGW("get rule failed.");
202         return;
203     }
204     long delayTime = 0;
205     if (freezeResultList.size() > 1) {
206         for (auto& i : freezeResultList) {
207             long window = i.GetWindow();
208             delayTime = std::max(delayTime, window);
209         }
210         if (delayTime == 0) {
211             delayTime = 10; // delay: 10s
212         }
213     }
214     ffrt::submit([this, watchPoint] { this->ProcessEvent(watchPoint); }, {}, {},
215         ffrt::task_attr().name("dfr_fre_detec").qos(ffrt::qos_default)
216         .delay(static_cast<unsigned long long>(delayTime) * toNanoSecondMultple));
217 }
218 
ProcessEvent(WatchPoint watchPoint)219 void FreezeDetectorPlugin::ProcessEvent(WatchPoint watchPoint)
220 {
221     HIVIEW_LOGD("received event domain=%{public}s, stringid=%{public}s",
222         watchPoint.GetDomain().c_str(), watchPoint.GetStringId().c_str());
223     if (freezeResolver_ == nullptr) {
224         this->SubUseCount();
225         return;
226     }
227 
228     auto ret = freezeResolver_->ProcessEvent(watchPoint);
229     if (ret < 0) {
230         HIVIEW_LOGE("FreezeResolver ProcessEvent filled.");
231     }
232     this->SubUseCount();
233 }
234 } // namespace HiviewDFX
235 } // namespace OHOS
236