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 #define LOG_TAG "UnifiedDataHelper"
16 #include "unified_data_helper.h"
17
18 #include "common_func.h"
19 #include "directory_ex.h"
20 #include "file_ex.h"
21 #include "file.h"
22 #include "file_uri.h"
23 #include "error_code.h"
24 #include "logger.h"
25 #include "tlv_util.h"
26 #include "udmf_conversion.h"
27 #include "udmf_meta.h"
28 #include "udmf_utils.h"
29 #include "utd_client.h"
30
31 namespace OHOS {
32 namespace UDMF {
33 constexpr mode_t MODE = 0700;
34 static constexpr int64_t MAX_IPC_RAW_DATA_SIZE = 127 * 1024 * 1024;
35 static constexpr int64_t MAX_SA_DRAG_RECORD_SIZE = 15 * 1024 * 1024 + 512 * 1024;
36
37 constexpr const char *TEMP_UNIFIED_DATA_ROOT_PATH = "data/storage/el2/base/temp/udata";
38 constexpr const char *TEMP_UNIFIED_DATA_SUFFIX = ".ud";
39 constexpr const char *TEMP_UNIFIED_DATA_FLAG = "temp_udmf_file_flag";
40 static constexpr int WITH_SUMMARY_FORMAT_VER = 1;
41 std::string UnifiedDataHelper::rootPath_ = "";
42
SetRootPath(const std::string & rootPath)43 void UnifiedDataHelper::SetRootPath(const std::string &rootPath)
44 {
45 rootPath_ = rootPath;
46 }
47
ExceedKVSizeLimit(UnifiedData & data)48 bool UnifiedDataHelper::ExceedKVSizeLimit(UnifiedData &data)
49 {
50 int64_t totalSize = 0;
51 for (const auto &record : data.GetRecords()) {
52 auto recordSize = record->GetSize();
53 if (recordSize > MAX_SA_DRAG_RECORD_SIZE) {
54 LOG_INFO(UDMF_FRAMEWORK, "Exceeded 15.5M record limit, recordSize:%{public}" PRId64 "!", recordSize);
55 return true;
56 }
57 totalSize += recordSize;
58 }
59 if (totalSize > MAX_IPC_RAW_DATA_SIZE) {
60 LOG_INFO(UDMF_FRAMEWORK, "Exceeded 127M data limit, totalSize:%{public}" PRId64 " !", totalSize);
61 return true;
62 }
63 return false;
64 }
65
IsTempUData(UnifiedData & data)66 bool UnifiedDataHelper::IsTempUData(UnifiedData &data)
67 {
68 auto records = data.GetRecords();
69 if (records.size() != 1) {
70 return false;
71 }
72 if (records[0] == nullptr || records[0]->GetType() != UDType::FILE) {
73 return false;
74 }
75 auto file = static_cast<File*>(records[0].get());
76 if (file == nullptr) {
77 LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
78 return false;
79 }
80 auto details = file->GetDetails();
81 if (details.find(TEMP_UNIFIED_DATA_FLAG) == details.end()) {
82 return false;
83 }
84 LOG_DEBUG(UDMF_FRAMEWORK, "exist temp unified data flag!");
85 return true;
86 }
87
CreateDirIfNotExist(const std::string & dirPath,const mode_t & mode)88 void UnifiedDataHelper::CreateDirIfNotExist(const std::string& dirPath, const mode_t& mode)
89 {
90 if (OHOS::FileExists(dirPath)) {
91 if (!OHOS::ForceRemoveDirectory(dirPath)) {
92 LOG_ERROR(UDMF_FRAMEWORK, "remove dir failed, errno: %{public}d.", errno);
93 }
94 }
95 bool success = OHOS::ForceCreateDirectory(dirPath);
96 if (!success) {
97 LOG_ERROR(UDMF_FRAMEWORK, "create dir failed, errno: %{public}d.", errno);
98 return;
99 }
100 if (mode != 0) {
101 chmod(dirPath.c_str(), mode);
102 }
103 }
104
GetSummary(const UnifiedData & data,Summary & summary)105 void UnifiedDataHelper::GetSummary(const UnifiedData &data, Summary &summary)
106 {
107 for (const auto &record : data.GetRecords()) {
108 CalRecordSummary(*record->GetEntries(), summary);
109 }
110 summary.version = WITH_SUMMARY_FORMAT_VER;
111 }
112
GetSummaryFromLoadInfo(const DataLoadInfo & dataLoadInfo,Summary & summary)113 void UnifiedDataHelper::GetSummaryFromLoadInfo(const DataLoadInfo &dataLoadInfo, Summary &summary)
114 {
115 summary.totalSize = dataLoadInfo.recordCount;
116 for (const auto &type : dataLoadInfo.types) {
117 summary.summary.emplace(type, 0);
118 }
119 }
120
Pack(UnifiedData & data)121 bool UnifiedDataHelper::Pack(UnifiedData &data)
122 {
123 UdmfConversion::InitValueObject(data);
124
125 Summary summary;
126 GetSummary(data, summary);
127
128 int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>
129 (std::chrono::system_clock::now().time_since_epoch()).count();
130 CreateDirIfNotExist(GetRootPath(), MODE);
131 std::string filePath = GetRootPath() + std::to_string(now) + TEMP_UNIFIED_DATA_SUFFIX;
132 if (!SaveUDataToFile(filePath, data)) {
133 LOG_ERROR(UDMF_FRAMEWORK, "fail to save unified data to file");
134 return false;
135 }
136 std::string uri = AppFileService::CommonFunc::GetUriFromPath(filePath);
137 auto fileRecord = std::make_shared<File>(uri);
138 UDDetails details;
139 details.insert(std::make_pair(TEMP_UNIFIED_DATA_FLAG, true));
140 for (auto &item : summary.summary) {
141 details.insert(std::make_pair(item.first, item.second));
142 }
143 fileRecord->SetDetails(details);
144 std::vector<std::shared_ptr<UnifiedRecord>> records {};
145 records.emplace_back(fileRecord);
146 data.SetRecords(records);
147 return true;
148 }
149
Unpack(UnifiedData & data)150 bool UnifiedDataHelper::Unpack(UnifiedData &data)
151 {
152 auto records = data.GetRecords();
153 if (records.size() != 1) {
154 return false;
155 }
156
157 auto file = static_cast<File*>(records[0].get());
158 if (file == nullptr) {
159 LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
160 return false;
161 }
162 UnifiedData tempData;
163 if (!LoadUDataFromFile(file->GetUri(), tempData)) {
164 LOG_ERROR(UDMF_FRAMEWORK, "Fail to load udata from file!");
165 return false;
166 }
167 data.SetRecords(tempData.GetRecords());
168 return true;
169 }
170
SaveUDataToFile(const std::string & dataFile,UnifiedData & data)171 bool UnifiedDataHelper::SaveUDataToFile(const std::string &dataFile, UnifiedData &data)
172 {
173 std::vector<uint8_t> dataBytes;
174 auto recordTlv = TLVObject(dataBytes);
175
176 std::FILE *file = fopen(dataFile.c_str(), "w+");
177 if (file == nullptr) {
178 LOG_ERROR(UDMF_FRAMEWORK, "failed to open file: errno is %{public}d", errno);
179 return false;
180 }
181 recordTlv.SetFile(file);
182 UdmfConversion::InitValueObject(data);
183 if (!TLVUtil::Writing(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
184 LOG_ERROR(UDMF_FRAMEWORK, "TLV Writing failed!");
185 return FileClose(file, false);
186 }
187 return FileClose(file, true);
188 }
189
LoadUDataFromFile(const std::string & dataFile,UnifiedData & data)190 bool UnifiedDataHelper::LoadUDataFromFile(const std::string &dataFile, UnifiedData &data)
191 {
192 std::vector<uint8_t> dataBytes;
193 auto recordTlv = TLVObject(dataBytes);
194 AppFileService::ModuleFileUri::FileUri fileUri(dataFile);
195 std::string path = fileUri.GetRealPath();
196 std::FILE *file = fopen(path.c_str(), "r");
197 if (file == nullptr) {
198 LOG_ERROR(UDMF_FRAMEWORK, "failed to open file, error:%{public}s", std::strerror(errno));
199 return false;
200 }
201 recordTlv.SetFile(file);
202
203 if (!TLVUtil::ReadTlv(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
204 LOG_ERROR(UDMF_FRAMEWORK, "TLV Reading failed!");
205 return FileClose(file, false);
206 }
207 UdmfConversion::ConvertRecordToSubclass(data);
208 return FileClose(file, true);
209 }
210
FileClose(std::FILE * file,bool status)211 bool UnifiedDataHelper::FileClose(std::FILE *file, bool status)
212 {
213 if (file == nullptr) {
214 return false;
215 }
216 if ((fclose(file) == EOF)) {
217 LOG_ERROR(UDMF_FRAMEWORK, "fclose is failed");
218 return false;
219 }
220 return status;
221 }
222
GetRootPath()223 std::string UnifiedDataHelper::GetRootPath()
224 {
225 if (rootPath_ == "") {
226 return TEMP_UNIFIED_DATA_ROOT_PATH;
227 }
228 return rootPath_;
229 }
230
ProcessBigData(UnifiedData & data,Intention intention,bool isSaInvoke)231 int32_t UnifiedDataHelper::ProcessBigData(UnifiedData &data, Intention intention, bool isSaInvoke)
232 {
233 if (!isSaInvoke) {
234 return UnifiedDataHelper::Pack(data) ? E_OK : E_FS_ERROR;
235 }
236 if (intention != Intention::UD_INTENTION_DRAG) {
237 LOG_ERROR(UDMF_SERVICE, "Non-Drag cannot be used to process big data when SA initiates a request");
238 return E_INVALID_PARAMETERS;
239 }
240 int64_t dataSize = 0;
241 for (const auto &record : data.GetRecords()) {
242 auto recordSize = record->GetSize();
243 if (recordSize > MAX_SA_DRAG_RECORD_SIZE) {
244 LOG_ERROR(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", recordSize);
245 return E_INVALID_PARAMETERS;
246 }
247 dataSize += recordSize;
248 }
249 if (dataSize > MAX_IPC_RAW_DATA_SIZE) {
250 LOG_ERROR(UDMF_SERVICE, "Exceeded ipc-send data limit, totalSize:%{public}" PRId64 " !", dataSize);
251 return E_INVALID_PARAMETERS;
252 }
253 LOG_DEBUG(UDMF_SERVICE, "Processing udmf data in memory");
254 return E_OK;
255 }
256
ProcessTypeId(const ValueType & value,std::string & typeId)257 void UnifiedDataHelper::ProcessTypeId(const ValueType &value, std::string &typeId)
258 {
259 if (!std::holds_alternative<std::shared_ptr<Object>>(value)) {
260 return;
261 }
262 auto object = std::get<std::shared_ptr<Object>>(value);
263 if (object->value_.find(UNIFORM_DATA_TYPE) == object->value_.end()) {
264 return;
265 }
266 if (object->value_.find(APPLICATION_DEFINED_RECORD_MARK) != object->value_.end()) {
267 typeId = UtdUtils::GetUtdIdFromUtdEnum(APPLICATION_DEFINED_RECORD);
268 } else if (std::get<std::string>(object->value_[UNIFORM_DATA_TYPE]) == GENERAL_FILE_URI &&
269 object->value_.find(FILE_TYPE) != object->value_.end()) {
270 std::string fileType = std::get<std::string>(object->value_[FILE_TYPE]);
271 if (!fileType.empty()) {
272 typeId = fileType;
273 }
274 }
275 }
276
CalRecordSummary(std::map<std::string,ValueType> & entry,Summary & summary)277 void UnifiedDataHelper::CalRecordSummary(std::map<std::string, ValueType> &entry, Summary &summary)
278 {
279 for (const auto &[utdId, value] : entry) {
280 auto typeId = utdId;
281 auto valueSize = ObjectUtils::GetValueSize(value, false);
282 ProcessTypeId(value, typeId);
283 auto specificIter = summary.specificSummary.find(typeId);
284 if (specificIter == summary.specificSummary.end()) {
285 summary.specificSummary[typeId] = valueSize;
286 } else {
287 summary.specificSummary[typeId] += valueSize;
288 }
289 FillSummaryFormat(typeId, utdId, summary);
290 if (utdId == GENERAL_FILE_URI) {
291 UpgradeToParentType(typeId);
292 }
293 auto it = summary.summary.find(typeId);
294 if (it == summary.summary.end()) {
295 summary.summary[typeId] = valueSize;
296 } else {
297 summary.summary[typeId] += valueSize;
298 }
299 summary.totalSize += valueSize;
300 }
301 }
302
FillSummaryFormat(const std::string & type,const std::string & utdId,Summary & summary)303 void UnifiedDataHelper::FillSummaryFormat(const std::string &type, const std::string &utdId, Summary &summary)
304 {
305 Uds_Type udsType = Uds_Type::UDS_OTHER;
306 auto find = UDS_UTD_TYPE_MAP.find(utdId);
307 if (find != UDS_UTD_TYPE_MAP.end()) {
308 udsType = find->second;
309 }
310 if (summary.summaryFormat.find(type) != summary.summaryFormat.end()) {
311 summary.summaryFormat[type].emplace_back(udsType);
312 } else {
313 summary.summaryFormat[type] = { udsType };
314 }
315 }
316
UpgradeToParentType(std::string & typeId)317 void UnifiedDataHelper::UpgradeToParentType(std::string &typeId)
318 {
319 std::string fileType = UnifiedDataUtils::GetBelongsToFileType(typeId);
320 if (!fileType.empty()) {
321 typeId = fileType;
322 return;
323 }
324 typeId = "general.file"; // When utdId is general.file-uri, the default parent type is general.file.
325 }
326
327 } // namespace UDMF
328 } // namespace OHOS