• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "sys_event_service_ohos.h"
17 
18 #include <codecvt>
19 #include <regex>
20 #include <set>
21 
22 #include "accesstoken_kit.h"
23 #include "event_query_wrapper_builder.h"
24 #include "hilog/log.h"
25 #include "if_system_ability_manager.h"
26 #include "ipc_skeleton.h"
27 #include "iservice_registry.h"
28 #include "ret_code.h"
29 #include "running_status_log_util.h"
30 #include "string_ex.h"
31 #include "system_ability_definition.h"
32 
33 using namespace std;
34 using namespace OHOS::HiviewDFX::EventStore;
35 
36 namespace OHOS {
37 namespace HiviewDFX {
38 namespace {
39 constexpr HiLogLabel LABEL = { LOG_CORE, 0xD002D10, "HiView-SysEventService" };
40 constexpr pid_t HID_ROOT = 0;
41 constexpr pid_t HID_SHELL = 2000;
42 constexpr pid_t HID_OHOS = 1000;
43 const std::vector<int> EVENT_TYPES = {1, 2, 3, 4}; // FAULT = 1, STATISTIC = 2 SECURITY = 3, BEHAVIOR = 4
44 constexpr uint32_t INVALID_EVENT_TYPE = 0;
45 const string READ_DFX_SYSEVENT_PERMISSION = "ohos.permission.READ_DFX_SYSEVENT";
46 
MatchContent(int type,const string & rule,const string & match)47 bool MatchContent(int type, const string& rule, const string& match)
48 {
49     if (match.empty()) {
50         return false;
51     }
52     switch (type) {
53         case RuleType::WHOLE_WORD:
54             return rule.empty() || match.compare(rule) == 0;
55         case RuleType::PREFIX:
56             return rule.empty() || match.find(rule) == 0;
57         case RuleType::REGULAR: {
58                 smatch result;
59                 const regex pattern(rule);
60                 return rule.empty() || regex_search(match, result, pattern);
61             }
62         default:
63             HiLog::Error(LABEL, "invalid rule type %{public}d.", type);
64             return false;
65     }
66 }
67 
MatchEventType(int rule,int match)68 bool MatchEventType(int rule, int match)
69 {
70     return rule == INVALID_EVENT_TYPE || rule == match;
71 }
72 
IsMatchedRule(const OHOS::HiviewDFX::SysEventRule & rule,const string & domain,const string & eventName,const string & tag,uint32_t eventType)73 bool IsMatchedRule(const OHOS::HiviewDFX::SysEventRule& rule, const string& domain,
74     const string& eventName, const string& tag, uint32_t eventType)
75 {
76     if (rule.tag.empty()) {
77         return MatchContent(rule.ruleType, rule.domain, domain)
78             && MatchContent(rule.ruleType, rule.eventName, eventName)
79             && MatchEventType(rule.eventType, eventType);
80     }
81     return MatchContent(rule.ruleType, rule.tag, tag)
82         && MatchEventType(rule.eventType, eventType);
83 }
84 
MatchRules(const SysEventRuleGroupOhos & rules,const string & domain,const string & eventName,const string & tag,uint32_t eventType)85 bool MatchRules(const SysEventRuleGroupOhos& rules, const string& domain, const string& eventName,
86     const string& tag, uint32_t eventType)
87 {
88     return any_of(rules.begin(), rules.end(), [domain, eventName, tag, eventType] (auto& rule) {
89         if (IsMatchedRule(rule, domain, eventName, tag, eventType)) {
90             string logFormat("rule type is %{public}d, domain is %{public}s, eventName is %{public}s, ");
91             logFormat.append("tag is %{public}s, eventType is %{public}u for matched");
92             HiLog::Debug(LABEL, logFormat.c_str(),
93                 rule.ruleType, rule.domain.empty() ? "empty" : rule.domain.c_str(),
94                 rule.eventName.empty() ? "empty" : rule.eventName.c_str(),
95                 rule.tag.empty() ? "empty" : rule.tag.c_str(), eventType);
96             return true;
97         }
98         return false;
99     });
100 }
101 
CheckEventListenerAddingValidity(const std::vector<SysEventRule> & rules,RegisteredListeners & listeners)102 int32_t CheckEventListenerAddingValidity(const std::vector<SysEventRule>& rules, RegisteredListeners& listeners)
103 {
104     size_t watchRuleCntLimit = 20; // count of listener rule for each watcher is limited to 20.
105     if (rules.size() > watchRuleCntLimit) {
106         OHOS::HiviewDFX::RunningStatusLogUtil::LogTooManyWatchRules(rules);
107         return ERR_TOO_MANY_WATCH_RULES;
108     }
109     size_t watcherTotalCntLimit = 30; // count of total watches is limited to 30.
110     if (listeners.size() >= watcherTotalCntLimit) {
111         OHOS::HiviewDFX::RunningStatusLogUtil::LogTooManyWatchers(watcherTotalCntLimit);
112         return ERR_TOO_MANY_WATCHERS;
113     }
114     return IPC_CALL_SUCCEED;
115 }
116 
CheckEventQueryingValidity(const SysEventQueryRuleGroupOhos & rules)117 int32_t CheckEventQueryingValidity(const SysEventQueryRuleGroupOhos& rules)
118 {
119     size_t queryRuleCntLimit = 10; // count of query rule for each querier is limited to 10.
120     if (rules.size() > queryRuleCntLimit) {
121         OHOS::HiviewDFX::RunningStatusLogUtil::LogTooManyQueryRules(rules);
122         return ERR_TOO_MANY_QUERY_RULES;
123     }
124     return IPC_CALL_SUCCEED;
125 }
126 }
127 
128 OHOS::HiviewDFX::NotifySysEvent SysEventServiceOhos::gISysEventNotify_;
129 sptr<OHOS::HiviewDFX::SysEventServiceOhos> SysEventServiceOhos::instance(new SysEventServiceOhos);
130 
GetInstance()131 sptr<OHOS::HiviewDFX::SysEventServiceOhos> SysEventServiceOhos::GetInstance()
132 {
133     return instance;
134 }
135 
StartService(SysEventServiceBase * service,const OHOS::HiviewDFX::NotifySysEvent notify)136 void SysEventServiceOhos::StartService(SysEventServiceBase *service,
137     const OHOS::HiviewDFX::NotifySysEvent notify)
138 {
139     gISysEventNotify_ = notify;
140     GetSysEventService(service);
141     sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
142     if (samgr == nullptr) {
143         HiLog::Error(LABEL, "failed to find SystemAbilityManager.");
144         return;
145     }
146     if (instance == nullptr) {
147         HiLog::Error(LABEL, "SysEventServiceOhos service is null.");
148         return;
149     }
150     int ret = samgr->AddSystemAbility(DFX_SYS_EVENT_SERVICE_ABILITY_ID, instance);
151     if (ret != 0) {
152         HiLog::Error(LABEL, "failed to add sys event service ability.");
153     }
154 }
155 
GetTagByDomainAndName(const string & eventDomain,const string & eventName)156 string SysEventServiceOhos::GetTagByDomainAndName(const string& eventDomain, const string& eventName)
157 {
158     if (getTagFunc_ == nullptr) {
159         return "";
160     }
161     return getTagFunc_(eventDomain, eventName);
162 }
163 
GetTypeByDomainAndName(const string & eventDomain,const string & eventName)164 uint32_t SysEventServiceOhos::GetTypeByDomainAndName(const string& eventDomain, const string& eventName)
165 {
166     if (getTypeFunc_ == nullptr) {
167         return INVALID_EVENT_TYPE;
168     }
169     return getTypeFunc_(eventDomain, eventName);
170 }
171 
OnSysEvent(std::shared_ptr<OHOS::HiviewDFX::SysEvent> & event)172 void SysEventServiceOhos::OnSysEvent(std::shared_ptr<OHOS::HiviewDFX::SysEvent>& event)
173 {
174     lock_guard<mutex> lock(mutex_);
175     for (auto listener = registeredListeners_.begin(); listener != registeredListeners_.end(); ++listener) {
176         SysEventCallbackPtrOhos callback = iface_cast<ISysEventCallback>(listener->first);
177         if (callback == nullptr) {
178             HiLog::Error(LABEL, "interface is null, no need to match rules.");
179             continue;
180         }
181         auto tag = GetTagByDomainAndName(event->domain_, event->eventName_);
182         auto eventType = GetTypeByDomainAndName(event->domain_, event->eventName_);
183         bool isMatched = MatchRules(listener->second.second, event->domain_, event->eventName_, tag, eventType);
184         HiLog::Debug(LABEL, "pid %{public}d rules match %{public}s.", listener->second.first,
185             isMatched ? "success" : "fail");
186         if (isMatched) {
187             callback->Handle(Str8ToStr16(event->domain_), Str8ToStr16(event->eventName_),
188                 static_cast<int>(event->what_), Str8ToStr16(event->jsonExtraInfo_));
189         }
190     }
191 }
192 
UpdateEventSeq(int64_t seq)193 void SysEventServiceOhos::UpdateEventSeq(int64_t seq)
194 {
195     curSeq.store(seq, std::memory_order_release);
196 }
197 
OnRemoteDied(const wptr<IRemoteObject> & remote)198 void SysEventServiceOhos::OnRemoteDied(const wptr<IRemoteObject>& remote)
199 {
200     if (remote == nullptr) {
201         HiLog::Error(LABEL, "remote is null");
202         return;
203     }
204     auto remoteObject = remote.promote();
205     if (remoteObject == nullptr) {
206         HiLog::Error(LABEL, "object in remote is null.");
207         return;
208     }
209     lock_guard<mutex> lock(mutex_);
210     if (debugModeCallback_ != nullptr) {
211         CallbackObjectOhos callbackObject = debugModeCallback_->AsObject();
212         if (callbackObject == remoteObject && isDebugMode_) {
213             HiLog::Error(LABEL, "quit debugmode.");
214             auto event = std::make_shared<Event>("SysEventSource");
215             event->messageType_ = Event::ENGINE_SYSEVENT_DEBUG_MODE;
216             event->SetValue("DEBUGMODE", "false");
217             gISysEventNotify_(event);
218             isDebugMode_ = false;
219         }
220     }
221     auto listener = registeredListeners_.find(remoteObject);
222     if (listener != registeredListeners_.end()) {
223         listener->first->RemoveDeathRecipient(deathRecipient_);
224         HiLog::Error(LABEL, "pid %{public}d has died and remove listener.", listener->second.first);
225         registeredListeners_.erase(listener);
226     }
227 }
228 
BindGetTagFunc(const GetTagByDomainNameFunc & getTagFunc)229 void SysEventServiceOhos::BindGetTagFunc(const GetTagByDomainNameFunc& getTagFunc)
230 {
231     getTagFunc_ = getTagFunc;
232 }
233 
BindGetTypeFunc(const GetTypeByDomainNameFunc & getTypeFunc)234 void SysEventServiceOhos::BindGetTypeFunc(const GetTypeByDomainNameFunc& getTypeFunc)
235 {
236     getTypeFunc_ = getTypeFunc;
237 }
238 
GetSysEventService(SysEventServiceBase * service)239 SysEventServiceBase* SysEventServiceOhos::GetSysEventService(SysEventServiceBase* service)
240 {
241     static SysEventServiceBase* ref = nullptr;
242     if (service != nullptr) {
243         ref = service;
244     }
245     return ref;
246 }
247 
AddListener(const std::vector<SysEventRule> & rules,const sptr<ISysEventCallback> & callback)248 int32_t SysEventServiceOhos::AddListener(const std::vector<SysEventRule>& rules,
249     const sptr<ISysEventCallback>& callback)
250 {
251     if (!HasAccessPermission()) {
252         return ERR_NO_PERMISSION;
253     }
254     auto checkRet = CheckEventListenerAddingValidity(rules, registeredListeners_);
255     if (checkRet != IPC_CALL_SUCCEED) {
256         return checkRet;
257     }
258     auto service = GetSysEventService();
259     if (service == nullptr) {
260         HiLog::Error(LABEL, "subscribe fail, sys event service is null.");
261         return ERR_REMOTE_SERVICE_IS_NULL;
262     }
263     if (callback == nullptr) {
264         HiLog::Error(LABEL, "subscribe fail, callback is null.");
265         return ERR_LISTENER_NOT_EXIST;
266     }
267     CallbackObjectOhos callbackObject = callback->AsObject();
268     if (callbackObject == nullptr) {
269         HiLog::Error(LABEL, "subscribe fail, object in callback is null.");
270         return ERR_LISTENER_STATUS_INVALID;
271     }
272     int32_t uid = IPCSkeleton::GetCallingUid();
273     int32_t pid = IPCSkeleton::GetCallingPid();
274     lock_guard<mutex> lock(mutex_);
275     pair<int32_t, SysEventRuleGroupOhos> rulesPair(pid, rules);
276     if (registeredListeners_.find(callbackObject) != registeredListeners_.end()) {
277         registeredListeners_[callbackObject] = rulesPair;
278         HiLog::Debug(LABEL, "uid %{public}d pid %{public}d listener has been added and update rules.", uid, pid);
279         return IPC_CALL_SUCCEED;
280     }
281     if (!callbackObject->AddDeathRecipient(deathRecipient_)) {
282         HiLog::Error(LABEL, "subscribe fail, can not add death recipient.");
283         return ERR_ADD_DEATH_RECIPIENT;
284     }
285     registeredListeners_.insert(make_pair(callbackObject, rulesPair));
286     HiLog::Debug(LABEL, "uid %{public}d pid %{public}d listener is added successfully, total is %{public}zu.",
287         uid, pid, registeredListeners_.size());
288     return IPC_CALL_SUCCEED;
289 }
290 
RemoveListener(const SysEventCallbackPtrOhos & callback)291 int32_t SysEventServiceOhos::RemoveListener(const SysEventCallbackPtrOhos& callback)
292 {
293     if (!HasAccessPermission()) {
294         return ERR_NO_PERMISSION;
295     }
296     auto service = GetSysEventService();
297     if (service == nullptr) {
298         HiLog::Error(LABEL, "sys event service is null.");
299         return ERR_REMOTE_SERVICE_IS_NULL;
300     }
301     if (callback == nullptr) {
302         HiLog::Error(LABEL, "callback is null.");
303         return ERR_LISTENER_NOT_EXIST;
304     }
305     CallbackObjectOhos callbackObject = callback->AsObject();
306     if (callbackObject == nullptr) {
307         HiLog::Error(LABEL, "object in callback is null.");
308         return ERR_LISTENER_STATUS_INVALID;
309     }
310     int32_t uid = IPCSkeleton::GetCallingUid();
311     int32_t pid = IPCSkeleton::GetCallingPid();
312     lock_guard<mutex> lock(mutex_);
313     if (registeredListeners_.empty()) {
314         HiLog::Debug(LABEL, "has no any listeners.");
315         return ERR_LISTENERS_EMPTY;
316     }
317     auto registeredListener = registeredListeners_.find(callbackObject);
318     if (registeredListener != registeredListeners_.end()) {
319         if (!callbackObject->RemoveDeathRecipient(deathRecipient_)) {
320             HiLog::Error(LABEL, "uid %{public}d pid %{public}d listener can not remove death recipient.", uid, pid);
321             return ERR_ADD_DEATH_RECIPIENT;
322         }
323         registeredListeners_.erase(registeredListener);
324         HiLog::Debug(LABEL, "uid %{public}d pid %{public}d has found listener and removes it.", uid, pid);
325         return IPC_CALL_SUCCEED;
326     } else {
327         HiLog::Debug(LABEL, "uid %{public}d pid %{public}d has not found listener.", uid, pid);
328         return ERR_LISTENER_NOT_EXIST;
329     }
330 }
331 
BuildEventQuery(std::shared_ptr<EventQueryWrapperBuilder> builder,const SysEventQueryRuleGroupOhos & rules)332 bool SysEventServiceOhos::BuildEventQuery(std::shared_ptr<EventQueryWrapperBuilder> builder,
333     const SysEventQueryRuleGroupOhos& rules)
334 {
335     if (builder == nullptr) {
336         return false;
337     }
338     auto callingUid = IPCSkeleton::GetCallingUid();
339     if (rules.empty() && (callingUid == HID_SHELL || callingUid == HID_ROOT ||
340         callingUid == HID_OHOS)) {
341         for (auto eventType : EVENT_TYPES) {
342             builder->Append(eventType);
343         }
344         return true;
345     }
346     return !any_of(rules.cbegin(), rules.cend(), [this, callingUid, &builder] (auto& rule) {
347         if (rule.domain.empty() && callingUid != HID_SHELL && callingUid != HID_ROOT &&
348             callingUid != HID_OHOS) {
349             return true;
350         }
351         return any_of(rule.eventList.cbegin(), rule.eventList.cend(),
352             [this, callingUid, &builder, &rule] (auto& eventName) {
353                 if (eventName.empty() && callingUid != HID_SHELL && callingUid != HID_ROOT &&
354                     callingUid != HID_OHOS) {
355                     return true;
356                 }
357                 auto eventType = this->GetTypeByDomainAndName(rule.domain, eventName);
358                 if ((!rule.domain.empty() && !eventName.empty() && eventType == INVALID_EVENT_TYPE) ||
359                     (eventType != INVALID_EVENT_TYPE && rule.eventType != INVALID_EVENT_TYPE &&
360                     eventType != rule.eventType)) {
361                     HiLog::Warn(LABEL, "domain=%{public}s, event name=%{public}s: "
362                         "event type configured is %{public}u, "
363                         "no match with query event type which is %{public}u.",
364                         rule.domain.c_str(), eventName.c_str(), eventType, rule.eventType);
365                     return false;
366                 }
367                 if (eventType != INVALID_EVENT_TYPE && rule.eventType == INVALID_EVENT_TYPE) {
368                     builder->Append(rule.domain, eventName, eventType, rule.condition);
369                     return false;
370                 }
371                 if (rule.eventType != INVALID_EVENT_TYPE) {
372                     builder->Append(rule.domain, eventName, rule.eventType, rule.condition);
373                     return false;
374                 }
375                 for (auto type : EVENT_TYPES) {
376                     builder->Append(rule.domain, eventName, type, rule.condition);
377                 }
378                 return false;
379             });
380     });
381 }
382 
Query(const QueryArgument & queryArgument,const SysEventQueryRuleGroupOhos & rules,const OHOS::sptr<OHOS::HiviewDFX::IQuerySysEventCallback> & callback)383 int32_t SysEventServiceOhos::Query(const QueryArgument& queryArgument, const SysEventQueryRuleGroupOhos& rules,
384     const OHOS::sptr<OHOS::HiviewDFX::IQuerySysEventCallback>& callback)
385 {
386     if (callback == nullptr) {
387         return ERR_LISTENER_NOT_EXIST;
388     }
389     if (!HasAccessPermission()) {
390         callback->OnComplete(ERR_NO_PERMISSION, 0, curSeq.load(std::memory_order_acquire));
391         return ERR_NO_PERMISSION;
392     }
393     auto checkRet = CheckEventQueryingValidity(rules);
394     if (checkRet != IPC_CALL_SUCCEED) {
395         callback->OnComplete(checkRet, 0, curSeq.load(std::memory_order_acquire));
396         return checkRet;
397     }
398     auto queryWrapperBuilder = std::make_shared<EventQueryWrapperBuilder>(queryArgument);
399     auto buildRet = BuildEventQuery(queryWrapperBuilder, rules);
400     if (!buildRet || queryWrapperBuilder == nullptr || !queryWrapperBuilder->IsValid()) {
401         HiLog::Warn(LABEL, "invalid query rule, exit sys event querying.");
402         callback->OnComplete(ERR_QUERY_RULE_INVALID, 0, curSeq.load(std::memory_order_acquire));
403         return ERR_QUERY_RULE_INVALID;
404     }
405     if (queryArgument.maxEvents == 0) {
406         HiLog::Warn(LABEL, "query count is 0, query complete directly.");
407         callback->OnComplete(IPC_CALL_SUCCEED, 0, curSeq.load(std::memory_order_acquire));
408         return IPC_CALL_SUCCEED;
409     }
410     auto queryWrapper = queryWrapperBuilder->Build();
411     if (queryWrapper == nullptr) {
412         HiLog::Warn(LABEL, "query wrapper build failed.");
413         callback->OnComplete(ERR_QUERY_RULE_INVALID, 0, curSeq.load(std::memory_order_acquire));
414         return ERR_QUERY_RULE_INVALID;
415     }
416     queryWrapper->SetMaxSequence(curSeq.load(std::memory_order_acquire));
417     auto queryRetCode = IPC_CALL_SUCCEED;
418     queryWrapper->Query(callback, queryRetCode);
419     return queryRetCode;
420 }
421 
HasAccessPermission() const422 bool SysEventServiceOhos::HasAccessPermission() const
423 {
424     using namespace Security::AccessToken;
425     auto callingUid = IPCSkeleton::GetCallingUid();
426     if (callingUid == HID_SHELL || callingUid == HID_ROOT || callingUid == HID_OHOS) {
427         return true;
428     }
429     auto tokenId = IPCSkeleton::GetFirstTokenID();
430     if (tokenId == 0) {
431         tokenId = IPCSkeleton::GetCallingTokenID();
432     }
433     if (AccessTokenKit::VerifyAccessToken(tokenId, READ_DFX_SYSEVENT_PERMISSION) == RET_SUCCESS) {
434         return true;
435     }
436     HiLog::Error(LABEL, "hiview service permission denial callingUid=%{public}d", callingUid);
437     return false;
438 }
439 
SetDebugMode(const SysEventCallbackPtrOhos & callback,bool mode)440 int32_t SysEventServiceOhos::SetDebugMode(const SysEventCallbackPtrOhos& callback, bool mode)
441 {
442     if (!HasAccessPermission()) {
443         return ERR_NO_PERMISSION;
444     }
445     if (mode == isDebugMode_) {
446         HiLog::Error(LABEL, "same config, no need set");
447         return ERR_DEBUG_MODE_SET_REPEAT;
448     }
449     auto event = std::make_shared<Event>("SysEventSource");
450     event->messageType_ = Event::ENGINE_SYSEVENT_DEBUG_MODE;
451     event->SetValue("DEBUGMODE", mode ? "true" : "false");
452     gISysEventNotify_(event);
453 
454     HiLog::Debug(LABEL, "set debug mode %{public}s", mode ? "true" : "false");
455     debugModeCallback_ = callback;
456     isDebugMode_ = mode;
457     return IPC_CALL_SUCCEED;
458 }
459 
Dump(int32_t fd,const std::vector<std::u16string> & args)460 int SysEventServiceOhos::Dump(int32_t fd, const std::vector<std::u16string> &args)
461 {
462     if (fd < 0) {
463         HiLog::Error(LABEL, "invalid fd.");
464         return -1;
465     }
466     dprintf(fd, "%s\n", "Hiview SysEventService");
467     return 0;
468 }
469 
OnRemoteDied(const wptr<IRemoteObject> & remote)470 void CallbackDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remote)
471 {
472     auto service = SysEventServiceOhos::GetInstance();
473     if (service == nullptr) {
474         HiLog::Error(LABEL, "SysEventServiceOhos service is null.");
475         return;
476     }
477     service->OnRemoteDied(remote);
478 }
479 }  // namespace HiviewDFX
480 }  // namespace OHOS