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_uri.h"
22 #include "error_code.h"
23 #include "logger.h"
24 #include "tlv_util.h"
25 #include "udmf_conversion.h"
26 #include "udmf_utils.h"
27 #include "file.h"
28
29 namespace OHOS {
30 namespace UDMF {
31 constexpr mode_t MODE = 0700;
32 static constexpr int64_t MAX_HAP_RECORD_SIZE = 2 * 1024 * 1024;
33 static constexpr int64_t MAX_HAP_DATA_SIZE = 4 * 1024 * 1024;
34 static constexpr int64_t MAX_IPC_RAW_DATA_SIZE = 128 * 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
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_HAP_RECORD_SIZE) {
54 LOG_INFO(UDMF_FRAMEWORK, "Exceeded 2M record limit, recordSize:%{public}" PRId64 "!", recordSize);
55 return true;
56 }
57 totalSize += recordSize;
58 }
59 if (totalSize > MAX_HAP_DATA_SIZE) {
60 LOG_INFO(UDMF_FRAMEWORK, "Exceeded 4M 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 %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
93 }
94 }
95 LOG_DEBUG(UDMF_FRAMEWORK, "ForceCreateDirectory, dir: %{public}s", dirPath.c_str());
96 bool success = OHOS::ForceCreateDirectory(dirPath);
97 if (!success) {
98 LOG_ERROR(UDMF_FRAMEWORK, "create dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
99 return;
100 }
101 if (mode != 0) {
102 chmod(dirPath.c_str(), mode);
103 }
104 }
105
GetSummary(const UnifiedData & data,Summary & summary)106 void UnifiedDataHelper::GetSummary(const UnifiedData &data, Summary &summary)
107 {
108 for (const auto &record : data.GetRecords()) {
109 CalRecordSummary(*record->GetEntries(), summary);
110 }
111 }
112
Pack(UnifiedData & data)113 bool UnifiedDataHelper::Pack(UnifiedData &data)
114 {
115 UdmfConversion::InitValueObject(data);
116
117 Summary summary;
118 GetSummary(data, summary);
119
120 int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>
121 (std::chrono::system_clock::now().time_since_epoch()).count();
122 CreateDirIfNotExist(GetRootPath(), MODE);
123 std::string filePath = GetRootPath() + std::to_string(now) + TEMP_UNIFIED_DATA_SUFFIX;
124 if (!SaveUDataToFile(filePath, data)) {
125 LOG_ERROR(UDMF_FRAMEWORK, "fail to save unified data to file");
126 return false;
127 }
128 std::string uri = AppFileService::CommonFunc::GetUriFromPath(filePath);
129 auto fileRecord = std::make_shared<File>(uri);
130 UDDetails details;
131 details.insert(std::make_pair(TEMP_UNIFIED_DATA_FLAG, true));
132 for (auto &item : summary.summary) {
133 details.insert(std::make_pair(item.first, item.second));
134 }
135 fileRecord->SetDetails(details);
136 std::vector<std::shared_ptr<UnifiedRecord>> records {};
137 records.emplace_back(fileRecord);
138 data.SetRecords(records);
139 return true;
140 }
141
Unpack(UnifiedData & data)142 bool UnifiedDataHelper::Unpack(UnifiedData &data)
143 {
144 auto records = data.GetRecords();
145 if (records.size() != 1) {
146 return false;
147 }
148
149 auto file = static_cast<File*>(records[0].get());
150 if (file == nullptr) {
151 LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
152 return false;
153 }
154 UnifiedData tempData;
155 if (!LoadUDataFromFile(file->GetUri(), tempData)) {
156 LOG_ERROR(UDMF_FRAMEWORK, "Fail to load udata from file!");
157 return false;
158 }
159 data.SetRecords(tempData.GetRecords());
160 return true;
161 }
162
SaveUDataToFile(const std::string & dataFile,UnifiedData & data)163 bool UnifiedDataHelper::SaveUDataToFile(const std::string &dataFile, UnifiedData &data)
164 {
165 std::vector<uint8_t> dataBytes;
166 auto recordTlv = TLVObject(dataBytes);
167
168 std::FILE *file = fopen(dataFile.c_str(), "w+");
169 if (file == nullptr) {
170 LOG_ERROR(UDMF_FRAMEWORK, "failed to open file: %{public}s, errno is %{public}d", dataFile.c_str(), errno);
171 return false;
172 }
173 recordTlv.SetFile(file);
174 UdmfConversion::InitValueObject(data);
175 if (!TLVUtil::Writing(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
176 LOG_ERROR(UDMF_FRAMEWORK, "TLV Writing failed!");
177 (void)fclose(file);
178 return false;
179 }
180 (void)fclose(file);
181 return true;
182 }
183
LoadUDataFromFile(const std::string & dataFile,UnifiedData & data)184 bool UnifiedDataHelper::LoadUDataFromFile(const std::string &dataFile, UnifiedData &data)
185 {
186 std::vector<uint8_t> dataBytes;
187 auto recordTlv = TLVObject(dataBytes);
188 AppFileService::ModuleFileUri::FileUri fileUri(dataFile);
189 std::string path = fileUri.GetRealPath();
190 std::FILE *file = fopen(path.c_str(), "r");
191 if (file == nullptr) {
192 LOG_ERROR(UDMF_FRAMEWORK, "failed to open file, error:%{public}s, srcdir:%{public}s, relPath:%{public}s",
193 std::strerror(errno),
194 dataFile.c_str(),
195 path.c_str());
196 return false;
197 }
198 recordTlv.SetFile(file);
199
200 if (!TLVUtil::ReadTlv(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
201 LOG_ERROR(UDMF_FRAMEWORK, "TLV Reading failed!");
202 (void)fclose(file);
203 return false;
204 }
205 UdmfConversion::ConvertRecordToSubclass(data);
206 (void)fclose(file);
207 return true;
208 }
209
GetRootPath()210 std::string UnifiedDataHelper::GetRootPath()
211 {
212 if (rootPath_ == "") {
213 return TEMP_UNIFIED_DATA_ROOT_PATH;
214 }
215 return rootPath_;
216 }
217
ProcessBigData(UnifiedData & data,Intention intention,bool isSaInvoke)218 int32_t UnifiedDataHelper::ProcessBigData(UnifiedData &data, Intention intention, bool isSaInvoke)
219 {
220 if (!isSaInvoke) {
221 return UnifiedDataHelper::Pack(data) ? E_OK : E_FS_ERROR;
222 }
223 if (intention != Intention::UD_INTENTION_DRAG) {
224 LOG_ERROR(UDMF_SERVICE, "Non-Drag cannot be used to process big data when SA initiates a request");
225 return E_INVALID_PARAMETERS;
226 }
227 int64_t dataSize = 0;
228 for (const auto &record : data.GetRecords()) {
229 auto recordSize = record->GetSize();
230 if (recordSize > MAX_SA_DRAG_RECORD_SIZE) {
231 LOG_ERROR(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", recordSize);
232 return E_INVALID_PARAMETERS;
233 }
234 dataSize += recordSize;
235 }
236 if (dataSize > MAX_IPC_RAW_DATA_SIZE) {
237 LOG_ERROR(UDMF_SERVICE, "Exceeded ipc-send data limit, totalSize:%{public}" PRId64 " !", dataSize);
238 return E_INVALID_PARAMETERS;
239 }
240 LOG_DEBUG(UDMF_SERVICE, "Processing udmf data in memory");
241 return E_OK;
242 }
243
CalRecordSummary(std::map<std::string,ValueType> & entry,Summary & summary)244 void UnifiedDataHelper::CalRecordSummary(std::map<std::string, ValueType> &entry, Summary &summary)
245 {
246 for (const auto &[utdId, value] : entry) {
247 auto typeId = utdId;
248 auto valueSize = ObjectUtils::GetValueSize(value, false);
249 if (std::holds_alternative<std::shared_ptr<Object>>(value)) {
250 auto object = std::get<std::shared_ptr<Object>>(value);
251 if (object->value_.find(APPLICATION_DEFINED_RECORD_MARK) != object->value_.end()) {
252 typeId = UtdUtils::GetUtdIdFromUtdEnum(APPLICATION_DEFINED_RECORD);
253 }
254 }
255 auto it = summary.summary.find(typeId);
256 if (it == summary.summary.end()) {
257 summary.summary[typeId] = valueSize;
258 } else {
259 summary.summary[typeId] += valueSize;
260 }
261 summary.totalSize += valueSize;
262 }
263 }
264
265 } // namespace UDMF
266 } // namespace OHOS