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