1 /*
2 * Copyright (c) 2023-2025 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 "os_event_listener.h"
16
17 #include <cerrno>
18 #include <fstream>
19 #include <sys/inotify.h>
20
21 #include "app_event_observer_mgr.h"
22 #include "app_event_store.h"
23 #include "application_context.h"
24 #include "event_json_util.h"
25 #include "file_util.h"
26 #include "hiappevent_base.h"
27 #include "hiappevent_common.h"
28 #include "hilog/log.h"
29 #include "parameters.h"
30 #include "storage_acl.h"
31
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN 0xD002D07
34
35 #undef LOG_TAG
36 #define LOG_TAG "OsEventListener"
37
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace {
41 constexpr int BUF_SIZE = 2048;
42 const std::string APP_EVENT_DIR = "/hiappevent";
43 const std::string RUNNING_ID_PROPERTY = "app_running_unique_id";
44 const std::string OS_LOG_PATH = "/data/storage/el2/log/hiappevent";
45 const std::string XATTR_NAME = "user.appevent";
46 const std::string KEY_HIAPPEVENT_ENABLE = "hiviewdfx.hiappevent.enable";
47
UpdateListenedEvents(const std::string & dir,uint64_t eventsMask)48 bool UpdateListenedEvents(const std::string& dir, uint64_t eventsMask)
49 {
50 if (!FileUtil::SetDirXattr(dir, XATTR_NAME, std::to_string(eventsMask))) {
51 HILOG_ERROR(LOG_CORE, "failed to set xattr dir=%{public}s, value=%{public}" PRIu64, dir.c_str(), eventsMask);
52 return false;
53 }
54 return true;
55 }
56
GetMaskFromDirXattr(const std::string & path)57 uint64_t GetMaskFromDirXattr(const std::string& path)
58 {
59 std::string value;
60 if (!FileUtil::GetDirXattr(path, XATTR_NAME, value)) {
61 HILOG_ERROR(LOG_CORE, "failed to get xattr.");
62 return 0;
63 }
64 HILOG_INFO(LOG_CORE, "getxattr success value=%{public}s.", value.c_str());
65 return static_cast<uint64_t>(std::strtoull(value.c_str(), nullptr, 0));
66 }
67 }
68
OsEventListener()69 OsEventListener::OsEventListener()
70 {
71 Init();
72 }
73
~OsEventListener()74 OsEventListener::~OsEventListener()
75 {
76 HILOG_INFO(LOG_CORE, "~OsEventListener");
77 inotifyThread_ = nullptr;
78 if (inotifyFd_ != -1) {
79 (void)inotify_rm_watch(inotifyFd_, inotifyWd_);
80 fdsan_close_with_tag(inotifyFd_, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN));
81 inotifyFd_ = -1;
82 }
83 }
84
Init()85 void OsEventListener::Init()
86 {
87 std::shared_ptr<OHOS::AbilityRuntime::ApplicationContext> context =
88 OHOS::AbilityRuntime::Context::GetApplicationContext();
89 if (context == nullptr) {
90 HILOG_ERROR(LOG_CORE, "Context is null.");
91 return;
92 }
93 if (context->GetCacheDir().empty()) {
94 HILOG_ERROR(LOG_CORE, "The files dir obtained from context is empty.");
95 return;
96 }
97 osEventPath_ = context->GetCacheDir() + APP_EVENT_DIR;
98 if (!FileUtil::IsFileExists(osEventPath_)) {
99 return;
100 }
101 // get subscribed events from dir xattr
102 osEventsMask_ = GetMaskFromDirXattr(osEventPath_);
103
104 // read os events from dir files
105 std::vector<std::string> files;
106 FileUtil::GetDirFiles(osEventPath_, files);
107 GetEventsFromFiles(files, historyEvents_);
108 for (auto& event : historyEvents_) {
109 int64_t eventSeq = AppEventStore::GetInstance().InsertEvent(event);
110 if (eventSeq <= 0) {
111 HILOG_WARN(LOG_CORE, "failed to store event to db");
112 continue;
113 }
114 event->SetSeq(eventSeq);
115 AppEventStore::GetInstance().QueryCustomParamsAdd2EventPack(event);
116 }
117 for (const auto& file : files) {
118 (void)FileUtil::RemoveFile(file);
119 }
120 }
121
GetEvents(std::vector<std::shared_ptr<AppEventPack>> & events)122 void OsEventListener::GetEvents(std::vector<std::shared_ptr<AppEventPack>>& events)
123 {
124 events = historyEvents_;
125 }
126
StartListening()127 bool OsEventListener::StartListening()
128 {
129 if (!OHOS::system::GetBoolParameter(KEY_HIAPPEVENT_ENABLE, true)) {
130 HILOG_INFO(LOG_CORE, "hiappevent is disabled");
131 RemoveOsEventDir();
132 return false;
133 }
134 return InitDir(OS_LOG_PATH) && InitDir(osEventPath_) && RegisterDirListener(osEventPath_);
135 }
136
RemoveOsEventDir()137 bool OsEventListener::RemoveOsEventDir()
138 {
139 inotifyStopFlag_ = true;
140 HILOG_INFO(LOG_CORE, "rm dir");
141 return FileUtil::ForceRemoveDirectory(osEventPath_) && FileUtil::ForceRemoveDirectory(OS_LOG_PATH);
142 }
143
InitDir(const std::string & dirPath)144 bool OsEventListener::InitDir(const std::string& dirPath)
145 {
146 if (!FileUtil::IsFileExists(dirPath) && !FileUtil::ForceCreateDirectory(dirPath)) {
147 HILOG_ERROR(LOG_CORE, "failed to create dir=%{public}s", dirPath.c_str());
148 return false;
149 }
150 if (OHOS::StorageDaemon::AclSetAccess(dirPath, "u:1201:rwx") != 0) {
151 HILOG_ERROR(LOG_CORE, "failed to set acl access dir=%{public}s", dirPath.c_str());
152 return false;
153 }
154 return true;
155 }
156
AddListenedEvents(uint64_t eventsMask)157 bool OsEventListener::AddListenedEvents(uint64_t eventsMask)
158 {
159 osEventsMask_ |= eventsMask;
160 HILOG_INFO(LOG_CORE, "add mask=%{public}" PRIu64 ", eventsMask=%{public}" PRIu64, eventsMask, osEventsMask_);
161 return UpdateListenedEvents(osEventPath_, osEventsMask_);
162 }
163
SetListenedEvents(uint64_t eventsMask)164 bool OsEventListener::SetListenedEvents(uint64_t eventsMask)
165 {
166 osEventsMask_ = eventsMask;
167 HILOG_INFO(LOG_CORE, "set eventsMask=%{public}" PRIu64, osEventsMask_);
168 return UpdateListenedEvents(osEventPath_, osEventsMask_);
169 }
170
RegisterDirListener(const std::string & dirPath)171 bool OsEventListener::RegisterDirListener(const std::string& dirPath)
172 {
173 if (inotifyFd_ < 0) {
174 inotifyFd_ = inotify_init();
175 if (inotifyFd_ < 0) {
176 HILOG_ERROR(LOG_CORE, "failed to inotify init : %s(%s).\n", strerror(errno), dirPath.c_str());
177 return false;
178 }
179 uint64_t ownerTag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN);
180 fdsan_exchange_owner_tag(inotifyFd_, 0, ownerTag);
181 inotifyWd_ = inotify_add_watch(inotifyFd_, dirPath.c_str(), IN_MOVED_TO | IN_CLOSE_WRITE);
182 if (inotifyWd_ < 0) {
183 HILOG_ERROR(LOG_CORE, "failed to add watch entry : %s(%s).\n", strerror(errno), dirPath.c_str());
184 fdsan_close_with_tag(inotifyFd_, ownerTag);
185 inotifyFd_ = -1;
186 return false;
187 }
188 HILOG_INFO(LOG_CORE, "inotify add watch dir=%{public}s successfully", dirPath.c_str());
189 }
190 inotifyStopFlag_ = false;
191 if (inotifyThread_ == nullptr) {
192 auto listenerPtr = shared_from_this();
193 inotifyThread_ = std::make_unique<std::thread>([listenerPtr] { listenerPtr->HandleDirEvent(); });
194 inotifyThread_->detach();
195 }
196 return true;
197 }
198
HandleDirEvent()199 void OsEventListener::HandleDirEvent()
200 {
201 if (pthread_setname_np(pthread_self(), "OS_AppEvent_Ls") != 0) {
202 HILOG_WARN(LOG_CORE, "Failed to set threadName, errno=%{public}d", errno);
203 }
204 while (!inotifyStopFlag_) {
205 char buffer[BUF_SIZE] = {0};
206 char* offset = buffer;
207 struct inotify_event* event = reinterpret_cast<struct inotify_event*>(buffer);
208 if (inotifyFd_ < 0) {
209 HILOG_ERROR(LOG_CORE, "Invalid inotify fd=%{public}d", inotifyFd_);
210 break;
211 }
212 int len = read(inotifyFd_, buffer, sizeof(buffer) - 1);
213 if (len <= 0) {
214 HILOG_ERROR(LOG_CORE, "failed to read event");
215 continue;
216 }
217 while ((offset - buffer) < len) {
218 if (event->len != 0) {
219 HILOG_INFO(LOG_CORE, "fileName: %{public}s event->mask: 0x%{public}x, event->len: %{public}d",
220 event->name, event->mask, event->len);
221 std::string fileName = FileUtil::GetFilePathByDir(osEventPath_, std::string(event->name));
222 HandleInotify(fileName);
223 }
224 uint32_t tmpLen = sizeof(struct inotify_event) + event->len;
225 event = reinterpret_cast<struct inotify_event*>(offset + tmpLen);
226 offset += tmpLen;
227 }
228 }
229 }
230
HandleInotify(const std::string & file)231 void OsEventListener::HandleInotify(const std::string& file)
232 {
233 std::vector<std::shared_ptr<AppEventPack>> events;
234 GetEventsFromFiles({file}, events);
235 AppEventObserverMgr::GetInstance().HandleEvents(events);
236 (void)FileUtil::RemoveFile(file);
237 }
238
GetEventsFromFiles(const std::vector<std::string> & files,std::vector<std::shared_ptr<AppEventPack>> & events)239 void OsEventListener::GetEventsFromFiles(
240 const std::vector<std::string>& files, std::vector<std::shared_ptr<AppEventPack>>& events)
241 {
242 for (const auto& filePath : files) {
243 std::vector<std::string> lines;
244 if (!FileUtil::LoadLinesFromFile(filePath, lines)) {
245 HILOG_ERROR(LOG_CORE, "file open failed, file=%{public}s", filePath.c_str());
246 continue;
247 }
248 for (const auto& line : lines) {
249 auto event = GetAppEventPackFromJson(line);
250 if (event != nullptr) {
251 events.emplace_back(event);
252 }
253 }
254 }
255 }
256
GetAppEventPackFromJson(const std::string & jsonStr)257 std::shared_ptr<AppEventPack> OsEventListener::GetAppEventPackFromJson(const std::string& jsonStr)
258 {
259 Json::Value eventJson;
260 if (!EventJsonUtil::GetJsonObjectFromJsonString(eventJson, jsonStr)) {
261 HILOG_ERROR(LOG_CORE, "parse event detail info failed, please check the style of json");
262 return nullptr;
263 }
264 auto appEventPack = std::make_shared<AppEventPack>();
265 appEventPack->SetDomain(EventJsonUtil::ParseString(eventJson, HiAppEvent::DOMAIN_PROPERTY));
266 appEventPack->SetName(EventJsonUtil::ParseString(eventJson, HiAppEvent::NAME_PROPERTY));
267 appEventPack->SetType(EventJsonUtil::ParseInt(eventJson, HiAppEvent::EVENT_TYPE_PROPERTY));
268 if (eventJson.isMember(HiAppEvent::PARAM_PROPERTY) && eventJson[HiAppEvent::PARAM_PROPERTY].isObject()) {
269 Json::Value paramsJson = eventJson[HiAppEvent::PARAM_PROPERTY];
270 if (paramsJson.isMember(RUNNING_ID_PROPERTY) && paramsJson[RUNNING_ID_PROPERTY].isString()) {
271 appEventPack->SetRunningId(paramsJson[RUNNING_ID_PROPERTY].asString());
272 paramsJson.removeMember(RUNNING_ID_PROPERTY);
273 }
274 appEventPack->SetParamStr(Json::FastWriter().write(paramsJson));
275 }
276 return appEventPack;
277 }
278 } // namespace HiviewDFX
279 } // namespace OHOS
280