1 /*
2  * Copyright (c) 2023-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 #include "app_event_observer.h"
16 
17 #include <sstream>
18 
19 #include "app_event.h"
20 #include "app_event_store.h"
21 #include "hiappevent_base.h"
22 #include "hiappevent_common.h"
23 #include "hilog/log.h"
24 
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN 0xD002D07
27 
28 #undef LOG_TAG
29 #define LOG_TAG "Observer"
30 
31 namespace OHOS {
32 namespace HiviewDFX {
33 namespace HiAppEvent {
34 namespace {
35 constexpr int MAX_SIZE_ON_EVENTS = 100;
36 constexpr uint64_t BIT_MASK = 1;
37 struct OsEventPosInfo {
38     std::string name;
39     EventType type;
40     uint8_t pos; // means position in binary
41 };
42 const std::vector<OsEventPosInfo> OS_EVENT_POS_INFOS = {
43     { EVENT_APP_CRASH, FAULT, 0 },
44     { EVENT_APP_FREEZE, FAULT, 1 },
45     { EVENT_APP_LAUNCH, BEHAVIOR, 2 },
46     { EVENT_SCROLL_JANK, FAULT, 3 },
47     { EVENT_CPU_USAGE_HIGH, FAULT, 4 },
48     { EVENT_BATTERY_USAGE, STATISTIC, 5 },
49     { EVENT_RESOURCE_OVERLIMIT, FAULT, 6 },
50     { EVENT_ADDRESS_SANITIZER, FAULT, 7 },
51     { EVENT_MAIN_THREAD_JANK, FAULT, 8 },
52     { EVENT_APP_START, BEHAVIOR, 9 },
53 };
54 
MeetNumberCondition(int currNum,int maxNum)55 bool MeetNumberCondition(int currNum, int maxNum)
56 {
57     return maxNum > 0 && currNum >= maxNum;
58 }
59 
GetStr(const std::unordered_set<std::string> & strSet)60 std::string GetStr(const std::unordered_set<std::string>& strSet)
61 {
62     if (strSet.empty()) {
63         return "[]";
64     }
65     std::stringstream strStream("[");
66     for (const auto& str : strSet) {
67         strStream << str << ",";
68     }
69     strStream.seekp(-1, std::ios_base::end); // -1 for delete ','
70     strStream << "]";
71     return strStream.str();
72 }
73 
GetStr(const std::vector<EventConfig> & eventConfigs)74 std::string GetStr(const std::vector<EventConfig>& eventConfigs)
75 {
76     if (eventConfigs.empty()) {
77         return "[]";
78     }
79     std::stringstream strStream("[");
80     for (const auto& eventConfig : eventConfigs) {
81         strStream << eventConfig.ToString() << ",";
82     }
83     strStream.seekp(-1, std::ios_base::end); // -1 for delete ','
84     strStream << "]";
85     return strStream.str();
86 }
87 }
88 
AppEventFilter(const std::string & domain,const std::unordered_set<std::string> & names,uint32_t types)89 AppEventFilter::AppEventFilter(const std::string& domain, const std::unordered_set<std::string>& names,
90     uint32_t types) : domain(domain), names(names), types(types)
91 {}
92 
AppEventFilter(const std::string & domain,uint32_t types)93 AppEventFilter::AppEventFilter(const std::string& domain, uint32_t types) : domain(domain), types(types)
94 {}
95 
IsValidEvent(std::shared_ptr<AppEventPack> event) const96 bool AppEventFilter::IsValidEvent(std::shared_ptr<AppEventPack> event) const
97 {
98     return IsValidEvent(event->GetDomain(), event->GetName(), event->GetType());
99 }
100 
IsValidEvent(const std::string & eventDomain,const std::string & eventName,int eventType) const101 bool AppEventFilter::IsValidEvent(const std::string& eventDomain, const std::string& eventName, int eventType) const
102 {
103     if (domain.empty()) {
104         return false;
105     }
106     if (!domain.empty() && domain != eventDomain) {
107         return false;
108     }
109     if (!names.empty() && (names.find(eventName) == names.end())) {
110         return false;
111     }
112     if (types != 0 && !(types & (1 << eventType))) { // 1: bit mask
113         return false;
114     }
115     return true;
116 }
117 
GetOsEventsMask() const118 uint64_t AppEventFilter::GetOsEventsMask() const
119 {
120     uint64_t mask = 0;
121     for (const auto& event : OS_EVENT_POS_INFOS) {
122         if (IsValidEvent(DOMAIN_OS, event.name, event.type)) {
123             mask |= (BIT_MASK << event.pos);
124         }
125     }
126     return mask;
127 }
128 
IsValidEvent(std::shared_ptr<AppEventPack> event) const129 bool EventConfig::IsValidEvent(std::shared_ptr<AppEventPack> event) const
130 {
131     if (domain.empty() && name.empty()) {
132         return false;
133     }
134     if (!domain.empty() && (domain != event->GetDomain())) {
135         return false;
136     }
137     if (!name.empty() && (name != event->GetName())) {
138         return false;
139     }
140     return true;
141 }
142 
IsRealTimeEvent(std::shared_ptr<AppEventPack> event) const143 bool EventConfig::IsRealTimeEvent(std::shared_ptr<AppEventPack> event) const
144 {
145     return IsValidEvent(event) && isRealTime;
146 }
147 
ToString() const148 std::string EventConfig::ToString() const
149 {
150     std::stringstream strStream;
151     strStream << "{" << domain << "," << name << "," << isRealTime << "}";
152     return strStream.str();
153 }
154 
ToString() const155 std::string TriggerCondition::ToString() const
156 {
157     std::stringstream strStream;
158     strStream << "{" << row << "," << size << "," << timeout << "," << onStartup << "," << onBackground << "}";
159     return strStream.str();
160 }
161 
ToString() const162 std::string ReportConfig::ToString() const
163 {
164     std::stringstream strStream;
165     strStream << "{" << name << "," << debugMode << "," << routeInfo << "," << appId << "," << triggerCond.ToString()
166         << "," << GetStr(userIdNames) << "," << GetStr(userPropertyNames) << "," << GetStr(eventConfigs) << "}";
167     return strStream.str();
168 }
169 
VerifyEvent(std::shared_ptr<AppEventPack> event)170 bool AppEventObserver::VerifyEvent(std::shared_ptr<AppEventPack> event)
171 {
172     if (filters_.empty()) {
173         return true;
174     }
175     auto it = std::find_if(filters_.begin(), filters_.end(), [event](const auto& filter) {
176         return filter.IsValidEvent(event);
177     });
178     return it != filters_.end();
179 }
180 
IsRealTimeEvent(std::shared_ptr<AppEventPack> event)181 bool AppEventObserver::IsRealTimeEvent(std::shared_ptr<AppEventPack> event)
182 {
183     const auto& eventConfigs = reportConfig_.eventConfigs;
184     if (eventConfigs.empty()) {
185         return false;
186     }
187     auto it = std::find_if(eventConfigs.begin(), eventConfigs.end(), [event](const auto& config) {
188         return config.IsRealTimeEvent(event);
189     });
190     return it != eventConfigs.end();
191 }
192 
ProcessEvent(std::shared_ptr<AppEventPack> event)193 void AppEventObserver::ProcessEvent(std::shared_ptr<AppEventPack> event)
194 {
195     HILOG_DEBUG(LOG_CORE, "observer=%{public}s start to process event", name_.c_str());
196     ++currCond_.row;
197     currCond_.size += static_cast<int>(event->GetEventStr().size());
198     if (MeetProcessCondition()) {
199         OnTrigger(currCond_);
200         ResetCurrCondition();
201     }
202 }
203 
MeetProcessCondition()204 bool AppEventObserver::MeetProcessCondition()
205 {
206     return MeetNumberCondition(currCond_.row, reportConfig_.triggerCond.row)
207         || MeetNumberCondition(currCond_.size, reportConfig_.triggerCond.size);
208 }
209 
ResetCurrCondition()210 void AppEventObserver::ResetCurrCondition()
211 {
212     currCond_.row = 0;
213     currCond_.size = 0;
214     currCond_.timeout = 0;
215 }
216 
OnTrigger(const TriggerCondition & triggerCond)217 void AppEventObserver::OnTrigger(const TriggerCondition& triggerCond)
218 {
219     std::vector<std::shared_ptr<AppEventPack>> events;
220     QueryEventsFromDb(events);
221     if (!events.empty()) {
222         OnEvents(events);
223     }
224 }
225 
QueryEventsFromDb(std::vector<std::shared_ptr<AppEventPack>> & events)226 void AppEventObserver::QueryEventsFromDb(std::vector<std::shared_ptr<AppEventPack>>& events)
227 {
228     if (AppEventStore::GetInstance().QueryEvents(events, seq_, MAX_SIZE_ON_EVENTS) != 0) {
229         HILOG_WARN(LOG_CORE, "failed to take data from observer=%{public}s, seq=%{public}" PRId64,
230             name_.c_str(), seq_);
231         return;
232     }
233     HILOG_INFO(LOG_CORE, "end to take data from observer=%{public}s, seq=%{public}" PRId64 ", size=%{public}zu",
234         name_.c_str(), seq_, events.size());
235 }
236 
ProcessTimeout()237 void AppEventObserver::ProcessTimeout()
238 {
239     currCond_.timeout += TIMEOUT_STEP;
240     if (!MeetTimeoutCondition()) {
241         return;
242     }
243     OnTrigger(currCond_);
244     ResetCurrCondition();
245 }
246 
MeetTimeoutCondition()247 bool AppEventObserver::MeetTimeoutCondition()
248 {
249     return MeetNumberCondition(currCond_.timeout, reportConfig_.triggerCond.timeout) && currCond_.row > 0;
250 }
251 
HasTimeoutCondition()252 bool AppEventObserver::HasTimeoutCondition()
253 {
254     return reportConfig_.triggerCond.timeout > 0 && currCond_.row > 0;
255 }
256 
ProcessStartup()257 void AppEventObserver::ProcessStartup()
258 {
259     if (!MeetStartupCondition()) {
260         return;
261     }
262     OnTrigger(currCond_);
263     ResetCurrCondition();
264 }
265 
MeetStartupCondition()266 bool AppEventObserver::MeetStartupCondition()
267 {
268     return reportConfig_.triggerCond.onStartup && currCond_.row > 0;
269 }
270 
ProcessBackground()271 void AppEventObserver::ProcessBackground()
272 {
273     if (!MeetBackgroundCondition()) {
274         return;
275     }
276     OnTrigger(currCond_);
277     ResetCurrCondition();
278 }
279 
MeetBackgroundCondition()280 bool AppEventObserver::MeetBackgroundCondition()
281 {
282     return reportConfig_.triggerCond.onBackground && currCond_.row > 0;
283 }
284 
GetName()285 std::string AppEventObserver::GetName()
286 {
287     return name_;
288 }
289 
GetSeq()290 int64_t AppEventObserver::GetSeq()
291 {
292     return seq_;
293 }
294 
GetReportConfig()295 ReportConfig AppEventObserver::GetReportConfig()
296 {
297     return reportConfig_;
298 }
299 
SetSeq(int64_t seq)300 void AppEventObserver::SetSeq(int64_t seq)
301 {
302     seq_ = seq;
303 }
304 
SetCurrCondition(const TriggerCondition & triggerCond)305 void AppEventObserver::SetCurrCondition(const TriggerCondition& triggerCond)
306 {
307     currCond_ = triggerCond;
308 }
309 
SetReportConfig(const ReportConfig & reportConfig)310 void AppEventObserver::SetReportConfig(const ReportConfig& reportConfig)
311 {
312     reportConfig_ = reportConfig;
313 
314     filters_.clear();
315     // if event configs is empty, do not report event
316     if (reportConfig.eventConfigs.empty()) {
317         filters_.emplace_back(AppEventFilter()); // invalid filter
318         return;
319     }
320 
321     for (const auto& eventConfig : reportConfig.eventConfigs) {
322         if (eventConfig.domain.empty() && eventConfig.name.empty()) {
323             continue;
324         }
325         std::unordered_set<std::string> names;
326         if (!eventConfig.name.empty()) {
327             names.emplace(eventConfig.name);
328         }
329         filters_.emplace_back(AppEventFilter(eventConfig.domain, names));
330     }
331 }
332 
GenerateHashCode()333 int64_t AppEventObserver::GenerateHashCode()
334 {
335     if (reportConfig_.name.empty()) {
336         // default hash code for watcher
337         return 0;
338     }
339     return (reportConfig_.configId > 0)
340         ? static_cast<int64_t>(reportConfig_.configId)
341         : static_cast<int64_t>(std::hash<std::string>{}(reportConfig_.ToString()));
342 }
343 
GetOsEventsMask()344 uint64_t AppEventObserver::GetOsEventsMask()
345 {
346     uint64_t mask = 0;
347     std::for_each(filters_.begin(), filters_.end(), [&mask](const auto& filter) {
348         mask |= filter.GetOsEventsMask();
349     });
350     return mask;
351 }
352 } // namespace HiAppEvent
353 } // namespace HiviewDFX
354 } // namespace OHOS
355