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