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