• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "storage_acl.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 const HiLogLabel LABEL = { LOG_CORE, HIAPPEVENT_DOMAIN, "HiAppEvent_OsEventListener" };
33 constexpr int BUF_SIZE = 2048;
34 const std::string APP_EVENT_DIR = "/hiappevent";
35 const std::string DOMAIN_PROPERTY = "domain";
36 const std::string NAME_PROPERTY = "name";
37 const std::string EVENT_TYPE_PROPERTY = "eventType";
38 const std::string PARAM_PROPERTY = "params";
39 }
40 
OsEventListener()41 OsEventListener::OsEventListener()
42 {
43     Init();
44 }
45 
~OsEventListener()46 OsEventListener::~OsEventListener()
47 {
48     HiLog::Info(LABEL, "~OsEventListener");
49     inotifyStopFlag_ = true;
50     inotifyThread_ = nullptr;
51     if (inotifyFd_ != -1) {
52         (void)inotify_rm_watch(inotifyFd_, inotifyWd_);
53         close(inotifyFd_);
54         inotifyFd_ = -1;
55     }
56 }
57 
Init()58 void OsEventListener::Init()
59 {
60     std::shared_ptr<OHOS::AbilityRuntime::ApplicationContext> context =
61         OHOS::AbilityRuntime::Context::GetApplicationContext();
62     if (context == nullptr) {
63         HiLog::Error(LABEL, "Context is null.");
64         return;
65     }
66     if (context->GetCacheDir().empty()) {
67         HiLog::Error(LABEL, "The files dir obtained from context is empty.");
68         return;
69     }
70     osEventPath_ = context->GetCacheDir() + APP_EVENT_DIR;
71 
72     std::vector<std::string> files;
73     FileUtil::GetDirFiles(osEventPath_, files);
74     GetEventsFromFiles(files, historyEvents_);
75     for (auto& event : historyEvents_) {
76         int64_t eventSeq = AppEventStore::GetInstance().InsertEvent(event);
77         if (eventSeq <= 0) {
78             HiLog::Warn(LABEL, "failed to store event to db");
79             continue;
80         }
81         event->SetSeq(eventSeq);
82     }
83     for (const auto& file : files) {
84         (void)FileUtil::RemoveFile(file);
85     }
86 }
87 
GetEvents(std::vector<std::shared_ptr<AppEventPack>> & events)88 void OsEventListener::GetEvents(std::vector<std::shared_ptr<AppEventPack>>& events)
89 {
90     events = historyEvents_;
91 }
92 
StartListening()93 bool OsEventListener::StartListening()
94 {
95     return InitDir(osEventPath_) && RegisterDirListener(osEventPath_);
96 }
97 
RemoveOsEventDir()98 bool OsEventListener::RemoveOsEventDir()
99 {
100     HiLog::Info(LABEL, "rm dir");
101     return FileUtil::ForceRemoveDirectory(osEventPath_);
102 }
103 
InitDir(const std::string & dirPath)104 bool OsEventListener::InitDir(const std::string& dirPath)
105 {
106     if (!FileUtil::IsFileExists(dirPath) && !FileUtil::ForceCreateDirectory(dirPath)) {
107         HiLog::Error(LABEL, "failed to create dir=%{public}s", dirPath.c_str());
108         return false;
109     }
110     if (OHOS::StorageDaemon::AclSetAccess(dirPath, "g:1201:rwx") != 0) {
111         HiLog::Error(LABEL, "failed to set acl access dir=%{public}s", dirPath.c_str());
112         return false;
113     }
114     return true;
115 }
116 
RegisterDirListener(const std::string & dirPath)117 bool OsEventListener::RegisterDirListener(const std::string& dirPath)
118 {
119     if (inotifyFd_ < 0) {
120         inotifyFd_ = inotify_init();
121         if (inotifyFd_ < 0) {
122             HiLog::Error(LABEL, "failed to inotify init : %s(%s).\n", strerror(errno), dirPath.c_str());
123             return false;
124         }
125         inotifyWd_ = inotify_add_watch(inotifyFd_, dirPath.c_str(), IN_MOVED_TO | IN_CLOSE_WRITE);
126         if (inotifyWd_ < 0) {
127             HiLog::Error(LABEL, "failed to add watch entry : %s(%s).\n", strerror(errno), dirPath.c_str());
128             close(inotifyFd_);
129             inotifyFd_ = -1;
130             return false;
131         }
132         HiLog::Info(LABEL, "inotify add watch dir=%{public}s successfully", dirPath.c_str());
133     }
134     inotifyStopFlag_ = false;
135     if (inotifyThread_ == nullptr) {
136         inotifyThread_ = std::make_unique<std::thread>(&OsEventListener::HandleDirEvent, this);
137         inotifyThread_->detach();
138     }
139     return true;
140 }
141 
HandleDirEvent()142 void OsEventListener::HandleDirEvent()
143 {
144     while (!inotifyStopFlag_) {
145         char buffer[BUF_SIZE] = {0};
146         char* offset = buffer;
147         struct inotify_event* event = reinterpret_cast<struct inotify_event*>(buffer);
148         if (inotifyFd_ < 0) {
149             HiLog::Error(LABEL, "Invalid inotify fd=%{public}d", inotifyFd_);
150             break;
151         }
152         int len = read(inotifyFd_, buffer, BUF_SIZE);
153         if (len <= 0) {
154             HiLog::Error(LABEL, "failed to read event");
155             continue;
156         }
157         while ((offset - buffer) < len) {
158             if (event->len != 0) {
159                 HiLog::Info(LABEL, "fileName: %{public}s event->mask: 0x%{public}x, event->len: %{public}d",
160                     event->name, event->mask, event->len);
161                 std::string fileName = FileUtil::GetFilePathByDir(osEventPath_, std::string(event->name));
162                 HandleInotify(fileName);
163             }
164             uint32_t tmpLen = sizeof(struct inotify_event) + event->len;
165             event = reinterpret_cast<struct inotify_event*>(offset + tmpLen);
166             offset += tmpLen;
167         }
168     }
169 }
170 
HandleInotify(const std::string & file)171 void OsEventListener::HandleInotify(const std::string& file)
172 {
173     std::vector<std::shared_ptr<AppEventPack>> events;
174     GetEventsFromFiles({file}, events);
175     AppEventObserverMgr::GetInstance().HandleEvents(events);
176     (void)FileUtil::RemoveFile(file);
177 }
178 
GetEventsFromFiles(const std::vector<std::string> & files,std::vector<std::shared_ptr<AppEventPack>> & events)179 void OsEventListener::GetEventsFromFiles(
180     const std::vector<std::string>& files, std::vector<std::shared_ptr<AppEventPack>>& events)
181 {
182     for (const auto& filePath : files) {
183         std::vector<std::string> lines;
184         if (!FileUtil::LoadLinesFromFile(filePath, lines)) {
185             HiLog::Error(LABEL, "file open failed, file=%{public}s", filePath.c_str());
186             continue;
187         }
188         for (const auto& line : lines) {
189             auto event = GetAppEventPackFromJson(line);
190             if (event != nullptr) {
191                 events.emplace_back(event);
192             }
193         }
194     }
195 }
196 
GetAppEventPackFromJson(const std::string & jsonStr)197 std::shared_ptr<AppEventPack> OsEventListener::GetAppEventPackFromJson(const std::string& jsonStr)
198 {
199     Json::Value eventJson;
200     Json::Reader reader(Json::Features::strictMode());
201     if (!reader.parse(jsonStr, eventJson)) {
202         HiLog::Error(LABEL, "parse event detail info failed, please check the style of json");
203         return nullptr;
204     }
205 
206     auto appEventPack = std::make_shared<AppEventPack>();
207     auto eventNameList = eventJson.getMemberNames();
208     for (auto it = eventNameList.cbegin(); it != eventNameList.cend(); ++it) {
209         auto propertyName = *it;
210         if (propertyName == DOMAIN_PROPERTY && eventJson[propertyName].isString()) {
211             appEventPack->SetDomain(eventJson[propertyName].asString());
212         } else if (propertyName == NAME_PROPERTY && eventJson[propertyName].isString()) {
213             appEventPack->SetName(eventJson[propertyName].asString());
214         } else if (propertyName == EVENT_TYPE_PROPERTY && eventJson[propertyName].isInt()) {
215             appEventPack->SetType(eventJson[propertyName].asInt());
216         } else if (propertyName == PARAM_PROPERTY) {
217             std::string paramStr = Json::FastWriter().write(eventJson[propertyName]);
218             appEventPack->SetParamStr(paramStr);
219         }
220     }
221     return appEventPack;
222 }
223 } // namespace HiviewDFX
224 } // namespace OHOS
225