• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 
16 #include "storage.h"
17 #include "serializer/serializer.h"
18 #include "utils/logger.h"
19 
20 #include <dirent.h>
21 #include <fstream>
22 #include <memory>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 
27 namespace ark::dprof {
28 /* static */
CreateByParams(const std::string & name,uint64_t hash,uint32_t pid,FeaturesMap && featuresMap)29 std::unique_ptr<AppData> AppData::CreateByParams(const std::string &name, uint64_t hash, uint32_t pid,
30                                                  FeaturesMap &&featuresMap)
31 {
32     std::unique_ptr<AppData> appData(new AppData);
33 
34     appData->commonInfo_.name = name;
35     appData->commonInfo_.hash = hash;
36     appData->commonInfo_.pid = pid;
37     appData->featuresMap_ = std::move(featuresMap);
38 
39     return appData;
40 }
41 
42 /* static */
CreateByBuffer(const std::vector<uint8_t> & buffer)43 std::unique_ptr<AppData> AppData::CreateByBuffer(const std::vector<uint8_t> &buffer)
44 {
45     std::unique_ptr<AppData> appData(new AppData);
46 
47     const uint8_t *data = buffer.data();
48     size_t size = buffer.size();
49     auto r = serializer::RawBufferToStruct<3>(data, size, appData->commonInfo_);  // 3
50     if (!r) {
51         LOG(ERROR, DPROF) << "Cannot deserialize buffer to common_info. Error: " << r.Error();
52         return nullptr;
53     }
54     ASSERT(r.Value() <= size);
55     data = serializer::ToUint8tPtr(serializer::ToUintPtr(data) + r.Value());
56     size -= r.Value();
57 
58     r = serializer::BufferToType(data, size, appData->featuresMap_);
59     if (!r) {
60         LOG(ERROR, DPROF) << "Cannot deserialize features_map. Error: " << r.Error();
61         return nullptr;
62     }
63     ASSERT(r.Value() <= size);
64     size -= r.Value();
65     if (size != 0) {
66         LOG(ERROR, DPROF) << "Cannot deserialize all buffer, unused buffer size: " << size;
67         return nullptr;
68     }
69 
70     return appData;
71 }
72 
ToBuffer(std::vector<uint8_t> & buffer) const73 bool AppData::ToBuffer(std::vector<uint8_t> &buffer) const
74 {
75     // 3
76     if (!serializer::StructToBuffer<3>(commonInfo_, buffer)) {
77         LOG(ERROR, DPROF) << "Cannot serialize common_info";
78         return false;
79     }
80     auto ret = serializer::TypeToBuffer(featuresMap_, buffer);
81     if (!ret) {
82         LOG(ERROR, DPROF) << "Cannot serialize features_map. Error: " << ret.Error();
83         return false;
84     }
85     return true;
86 }
87 
88 /* static */
Create(const std::string & storageDir,bool createDir)89 std::unique_ptr<AppDataStorage> AppDataStorage::Create(const std::string &storageDir, bool createDir)
90 {
91     if (storageDir.empty()) {
92         LOG(ERROR, DPROF) << "Storage directory is not set";
93         return nullptr;
94     }
95 
96     struct stat statBuffer {};
97     if (::stat(storageDir.c_str(), &statBuffer) == 0) {
98         // NOLINTNEXTLINE(hicpp-signed-bitwise)
99         if (S_ISDIR(statBuffer.st_mode)) {
100             return std::unique_ptr<AppDataStorage>(new AppDataStorage(storageDir));
101         }
102 
103         LOG(ERROR, DPROF) << storageDir << " is already exists and it is neither directory";
104         return nullptr;
105     }
106 
107     if (createDir) {
108         // NOLINTNEXTLINE(hicpp-signed-bitwise)
109         if (::mkdir(storageDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
110             PLOG(ERROR, DPROF) << "mkdir() failed";
111             return nullptr;
112         }
113         return std::unique_ptr<AppDataStorage>(new AppDataStorage(storageDir));
114     }
115 
116     return nullptr;
117 }
118 
SaveAppData(const AppData & appData)119 bool AppDataStorage::SaveAppData(const AppData &appData)
120 {
121     std::vector<uint8_t> buffer;
122     if (!appData.ToBuffer(buffer)) {
123         LOG(ERROR, DPROF) << "Cannot serialize AppData to buffer";
124         return false;
125     }
126 
127     // Save buffer to file
128     std::string fileName = MakeAppPath(appData.GetName(), appData.GetHash(), appData.GetPid());
129     std::ofstream file(fileName, std::ios::binary);
130     if (!file.is_open()) {
131         LOG(ERROR, DPROF) << "Cannot open file: " << fileName;
132         return false;
133     }
134     file.write(reinterpret_cast<const char *>(buffer.data()), buffer.size());
135     if (file.bad()) {
136         LOG(ERROR, DPROF) << "Cannot write AppData to file: " << fileName;
137         return false;
138     }
139 
140     LOG(DEBUG, DPROF) << "Save AppData to file: " << fileName;
141     return true;
142 }
143 
DoReadDir(DIR * dirp)144 struct dirent *DoReadDir(DIR *dirp)
145 {
146     errno = 0;
147     return ::readdir(dirp);
148 }
149 
ForEachApps(const std::function<bool (std::unique_ptr<AppData> &&)> & callback) const150 void AppDataStorage::ForEachApps(const std::function<bool(std::unique_ptr<AppData> &&)> &callback) const
151 {
152     using UniqueDir = std::unique_ptr<DIR, void (*)(DIR *)>;
153     UniqueDir dir(::opendir(storageDir_.c_str()), [](DIR *directory) {
154         if (::closedir(directory) == -1) {
155             PLOG(FATAL, DPROF) << "closedir() failed";
156         }
157     });
158     if (dir.get() == nullptr) {
159         PLOG(FATAL, DPROF) << "opendir() failed, dir=" << storageDir_;
160         return;
161     }
162 
163     struct dirent *ent;
164     while ((ent = DoReadDir(dir.get())) != nullptr) {
165         if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
166             // Skip a valid name
167             continue;
168         }
169 
170         if (ent->d_type != DT_REG) {
171             LOG(ERROR, DPROF) << "Not a regular file: " << ent->d_name;
172             continue;
173         }
174 
175         std::string path = storageDir_ + "/" + ent->d_name;
176         struct stat statbuf {};
177         if (stat(path.c_str(), &statbuf) == -1) {
178             PLOG(ERROR, DPROF) << "stat() failed, path=" << path;
179             continue;
180         }
181         size_t fileSize = statbuf.st_size;
182 
183         if (fileSize > MAX_BUFFER_SIZE) {
184             LOG(ERROR, DPROF) << "File is to large: " << path;
185             continue;
186         }
187 
188         // Read file
189         std::ifstream file(path, std::ios::binary);
190         if (!file.is_open()) {
191             LOG(ERROR, DPROF) << "Cannot open file: " << path;
192             continue;
193         }
194         std::vector<uint8_t> buffer;
195         buffer.reserve(fileSize);
196         buffer.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
197 
198         auto appData = AppData::CreateByBuffer(buffer);
199         if (!appData) {
200             LOG(ERROR, DPROF) << "Cannot deserialize file: " << path;
201             continue;
202         }
203 
204         if (!callback(std::move(appData))) {
205             break;
206         }
207     }
208 }
209 
MakeAppPath(const std::string & name,uint64_t hash,uint32_t pid) const210 std::string AppDataStorage::MakeAppPath(const std::string &name, uint64_t hash, uint32_t pid) const
211 {
212     ASSERT(!storageDir_.empty());
213     ASSERT(!name.empty());
214 
215     std::stringstream str;
216     str << storageDir_ << "/" << name << "@" << pid << "@" << hash;
217     return str.str();
218 }
219 }  // namespace ark::dprof
220