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