• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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