1 /**
2 * Copyright (c) 2021-2022 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 panda::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->common_info_.name = name;
35 appData->common_info_.hash = hash;
36 appData->common_info_.pid = pid;
37 appData->features_map_ = 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->common_info_); // 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->features_map_);
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>(common_info_, buffer)) {
77 LOG(ERROR, DPROF) << "Cannot serialize common_info";
78 return false;
79 }
80 auto ret = serializer::TypeToBuffer(features_map_, 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 };
98 if (::stat(storageDir.c_str(), &statBuffer) == 0) {
99 // NOLINTNEXTLINE(hicpp-signed-bitwise)
100 if (S_ISDIR(statBuffer.st_mode)) {
101 return std::unique_ptr<AppDataStorage>(new AppDataStorage(storageDir));
102 }
103
104 LOG(ERROR, DPROF) << storageDir << " is already exists and it is neither directory";
105 return nullptr;
106 }
107
108 if (createDir) {
109 // NOLINTNEXTLINE(hicpp-signed-bitwise)
110 if (::mkdir(storageDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
111 PLOG(ERROR, DPROF) << "mkdir() failed";
112 return nullptr;
113 }
114 return std::unique_ptr<AppDataStorage>(new AppDataStorage(storageDir));
115 }
116
117 return nullptr;
118 }
119
SaveAppData(const AppData & appData)120 bool AppDataStorage::SaveAppData(const AppData &appData)
121 {
122 std::vector<uint8_t> buffer;
123 if (!appData.ToBuffer(buffer)) {
124 LOG(ERROR, DPROF) << "Cannot serialize AppData to buffer";
125 return false;
126 }
127
128 // Save buffer to file
129 std::string fileName = MakeAppPath(appData.GetName(), appData.GetHash(), appData.GetPid());
130 std::ofstream file(fileName, std::ios::binary);
131 if (!file.is_open()) {
132 LOG(ERROR, DPROF) << "Cannot open file: " << fileName;
133 return false;
134 }
135 file.write(reinterpret_cast<const char *>(buffer.data()), buffer.size());
136 if (file.bad()) {
137 LOG(ERROR, DPROF) << "Cannot write AppData to file: " << fileName;
138 return false;
139 }
140
141 LOG(DEBUG, DPROF) << "Save AppData to file: " << fileName;
142 return true;
143 }
144
DoReadDir(DIR * dirp)145 struct dirent *DoReadDir(DIR *dirp)
146 {
147 errno = 0;
148 return ::readdir(dirp);
149 }
150
ForEachApps(const std::function<bool (std::unique_ptr<AppData> &&)> & callback) const151 void AppDataStorage::ForEachApps(const std::function<bool(std::unique_ptr<AppData> &&)> &callback) const
152 {
153 using UniqueDir = std::unique_ptr<DIR, void (*)(DIR *)>;
154 UniqueDir dir(::opendir(storage_dir_.c_str()), [](DIR *directory) {
155 if (::closedir(directory) == -1) {
156 PLOG(FATAL, DPROF) << "closedir() failed";
157 }
158 });
159 if (dir.get() == nullptr) {
160 PLOG(FATAL, DPROF) << "opendir() failed, dir=" << storage_dir_;
161 return;
162 }
163
164 struct dirent *ent;
165 while ((ent = DoReadDir(dir.get())) != nullptr) {
166 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
167 // Skip a valid name
168 continue;
169 }
170
171 if (ent->d_type != DT_REG) {
172 LOG(ERROR, DPROF) << "Not a regular file: " << ent->d_name;
173 continue;
174 }
175
176 std::string path = storage_dir_ + "/" + ent->d_name;
177 struct stat statbuf {
178 };
179 if (stat(path.c_str(), &statbuf) == -1) {
180 PLOG(ERROR, DPROF) << "stat() failed, path=" << path;
181 continue;
182 }
183 size_t fileSize = statbuf.st_size;
184
185 if (fileSize > MAX_BUFFER_SIZE) {
186 LOG(ERROR, DPROF) << "File is to large: " << path;
187 continue;
188 }
189
190 // Read file
191 std::ifstream file(path, std::ios::binary);
192 if (!file.is_open()) {
193 LOG(ERROR, DPROF) << "Cannot open file: " << path;
194 continue;
195 }
196 std::vector<uint8_t> buffer;
197 buffer.reserve(fileSize);
198 buffer.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
199
200 auto appData = AppData::CreateByBuffer(buffer);
201 if (!appData) {
202 LOG(ERROR, DPROF) << "Cannot deserialize file: " << path;
203 continue;
204 }
205
206 if (!callback(std::move(appData))) {
207 break;
208 }
209 }
210 }
211
MakeAppPath(const std::string & name,uint64_t hash,uint32_t pid) const212 std::string AppDataStorage::MakeAppPath(const std::string &name, uint64_t hash, uint32_t pid) const
213 {
214 ASSERT(!storage_dir_.empty());
215 ASSERT(!name.empty());
216
217 std::stringstream str;
218 str << storage_dir_ << "/" << name << "@" << pid << "@" << hash;
219 return str.str();
220 }
221 } // namespace panda::dprof
222