• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 namespace OHOS {
31 namespace UDMF {
32 constexpr mode_t MODE = 0700;
33 static constexpr int64_t MAX_IPC_RAW_DATA_SIZE = 127 * 1024 * 1024;
34 static constexpr int64_t MAX_SA_DRAG_RECORD_SIZE  = 15 * 1024 * 1024 + 512 * 1024;
35 
36 constexpr const char *TEMP_UNIFIED_DATA_ROOT_PATH = "data/storage/el2/base/temp/udata";
37 constexpr const char *TEMP_UNIFIED_DATA_SUFFIX = ".ud";
38 constexpr const char *TEMP_UNIFIED_DATA_FLAG = "temp_udmf_file_flag";
39 
40 std::string UnifiedDataHelper::rootPath_ = "";
41 
SetRootPath(const std::string & rootPath)42 void UnifiedDataHelper::SetRootPath(const std::string &rootPath)
43 {
44     rootPath_ = rootPath;
45 }
46 
ExceedKVSizeLimit(UnifiedData & data)47 bool UnifiedDataHelper::ExceedKVSizeLimit(UnifiedData &data)
48 {
49     int64_t totalSize = 0;
50     for (const auto &record : data.GetRecords()) {
51         auto recordSize = record->GetSize();
52         if (recordSize > MAX_SA_DRAG_RECORD_SIZE) {
53             LOG_INFO(UDMF_FRAMEWORK, "Exceeded 15.5M record limit, recordSize:%{public}" PRId64 "!", recordSize);
54             return true;
55         }
56         totalSize += recordSize;
57     }
58     if (totalSize > MAX_IPC_RAW_DATA_SIZE) {
59         LOG_INFO(UDMF_FRAMEWORK, "Exceeded 127M data limit, totalSize:%{public}" PRId64 " !", totalSize);
60         return true;
61     }
62     return false;
63 }
64 
IsTempUData(UnifiedData & data)65 bool UnifiedDataHelper::IsTempUData(UnifiedData &data)
66 {
67     auto records = data.GetRecords();
68     if (records.size() != 1) {
69         return false;
70     }
71     if (records[0] == nullptr || records[0]->GetType() != UDType::FILE) {
72         return false;
73     }
74     auto file = static_cast<File*>(records[0].get());
75     if (file == nullptr) {
76         LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
77         return false;
78     }
79     auto details = file->GetDetails();
80     if (details.find(TEMP_UNIFIED_DATA_FLAG) == details.end()) {
81         return false;
82     }
83     LOG_DEBUG(UDMF_FRAMEWORK, "exist temp unified data flag!");
84     return true;
85 }
86 
CreateDirIfNotExist(const std::string & dirPath,const mode_t & mode)87 void UnifiedDataHelper::CreateDirIfNotExist(const std::string& dirPath, const mode_t& mode)
88 {
89     if (OHOS::FileExists(dirPath)) {
90         if (!OHOS::ForceRemoveDirectory(dirPath)) {
91             LOG_ERROR(UDMF_FRAMEWORK, "remove dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), errno);
92         }
93     }
94     LOG_DEBUG(UDMF_FRAMEWORK, "ForceCreateDirectory, dir: %{public}s", dirPath.c_str());
95     bool success = OHOS::ForceCreateDirectory(dirPath);
96     if (!success) {
97         LOG_ERROR(UDMF_FRAMEWORK, "create dir %{public}s failed, errno: %{public}d.", dirPath.c_str(), 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 }
111 
Pack(UnifiedData & data)112 bool UnifiedDataHelper::Pack(UnifiedData &data)
113 {
114     UdmfConversion::InitValueObject(data);
115 
116     Summary summary;
117     GetSummary(data, summary);
118 
119     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>
120                     (std::chrono::system_clock::now().time_since_epoch()).count();
121     CreateDirIfNotExist(GetRootPath(), MODE);
122     std::string filePath = GetRootPath() + std::to_string(now) + TEMP_UNIFIED_DATA_SUFFIX;
123     if (!SaveUDataToFile(filePath, data)) {
124         LOG_ERROR(UDMF_FRAMEWORK, "fail to save unified data to file");
125         return false;
126     }
127     std::string uri = AppFileService::CommonFunc::GetUriFromPath(filePath);
128     auto fileRecord = std::make_shared<File>(uri);
129     UDDetails details;
130     details.insert(std::make_pair(TEMP_UNIFIED_DATA_FLAG, true));
131     for (auto &item : summary.summary) {
132         details.insert(std::make_pair(item.first, item.second));
133     }
134     fileRecord->SetDetails(details);
135     std::vector<std::shared_ptr<UnifiedRecord>> records {};
136     records.emplace_back(fileRecord);
137     data.SetRecords(records);
138     return true;
139 }
140 
Unpack(UnifiedData & data)141 bool UnifiedDataHelper::Unpack(UnifiedData &data)
142 {
143     auto records = data.GetRecords();
144     if (records.size() != 1) {
145         return false;
146     }
147 
148     auto file = static_cast<File*>(records[0].get());
149     if (file == nullptr) {
150         LOG_ERROR(UDMF_FRAMEWORK, "Invalid file record!");
151         return false;
152     }
153     UnifiedData tempData;
154     if (!LoadUDataFromFile(file->GetUri(), tempData)) {
155         LOG_ERROR(UDMF_FRAMEWORK, "Fail to load udata from file!");
156         return false;
157     }
158     data.SetRecords(tempData.GetRecords());
159     return true;
160 }
161 
SaveUDataToFile(const std::string & dataFile,UnifiedData & data)162 bool UnifiedDataHelper::SaveUDataToFile(const std::string &dataFile, UnifiedData &data)
163 {
164     std::vector<uint8_t> dataBytes;
165     auto recordTlv = TLVObject(dataBytes);
166 
167     std::FILE *file = fopen(dataFile.c_str(), "w+");
168     if (file == nullptr) {
169         LOG_ERROR(UDMF_FRAMEWORK, "failed to open file: %{public}s, errno is %{public}d", dataFile.c_str(), errno);
170         return false;
171     }
172     recordTlv.SetFile(file);
173     UdmfConversion::InitValueObject(data);
174     if (!TLVUtil::Writing(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
175         LOG_ERROR(UDMF_FRAMEWORK, "TLV Writing failed!");
176         (void)fclose(file);
177         return false;
178     }
179     (void)fclose(file);
180     return true;
181 }
182 
LoadUDataFromFile(const std::string & dataFile,UnifiedData & data)183 bool UnifiedDataHelper::LoadUDataFromFile(const std::string &dataFile, UnifiedData &data)
184 {
185     std::vector<uint8_t> dataBytes;
186     auto recordTlv = TLVObject(dataBytes);
187     AppFileService::ModuleFileUri::FileUri fileUri(dataFile);
188     std::string path = fileUri.GetRealPath();
189     std::FILE *file = fopen(path.c_str(), "r");
190     if (file == nullptr) {
191         LOG_ERROR(UDMF_FRAMEWORK, "failed to open file, error:%{public}s, srcdir:%{public}s, relPath:%{public}s",
192                   std::strerror(errno),
193                   dataFile.c_str(),
194                   path.c_str());
195         return false;
196     }
197     recordTlv.SetFile(file);
198 
199     if (!TLVUtil::ReadTlv(data, recordTlv, TAG::TAG_UNIFIED_DATA)) {
200         LOG_ERROR(UDMF_FRAMEWORK, "TLV Reading failed!");
201         (void)fclose(file);
202         return false;
203     }
204     UdmfConversion::ConvertRecordToSubclass(data);
205     (void)fclose(file);
206     return true;
207 }
208 
GetRootPath()209 std::string UnifiedDataHelper::GetRootPath()
210 {
211     if (rootPath_ == "") {
212         return TEMP_UNIFIED_DATA_ROOT_PATH;
213     }
214     return rootPath_;
215 }
216 
ProcessBigData(UnifiedData & data,Intention intention,bool isSaInvoke)217 int32_t UnifiedDataHelper::ProcessBigData(UnifiedData &data, Intention intention, bool isSaInvoke)
218 {
219     if (!isSaInvoke) {
220         return UnifiedDataHelper::Pack(data) ? E_OK : E_FS_ERROR;
221     }
222     if (intention != Intention::UD_INTENTION_DRAG) {
223         LOG_ERROR(UDMF_SERVICE, "Non-Drag cannot be used to process big data when SA initiates a request");
224         return E_INVALID_PARAMETERS;
225     }
226     int64_t dataSize = 0;
227     for (const auto &record : data.GetRecords()) {
228         auto recordSize = record->GetSize();
229         if (recordSize > MAX_SA_DRAG_RECORD_SIZE) {
230             LOG_ERROR(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", recordSize);
231             return E_INVALID_PARAMETERS;
232         }
233         dataSize += recordSize;
234     }
235     if (dataSize > MAX_IPC_RAW_DATA_SIZE) {
236         LOG_ERROR(UDMF_SERVICE, "Exceeded ipc-send data limit, totalSize:%{public}" PRId64 " !", dataSize);
237         return E_INVALID_PARAMETERS;
238     }
239     LOG_DEBUG(UDMF_SERVICE, "Processing udmf data in memory");
240     return E_OK;
241 }
242 
ProcessTypeId(const ValueType & value,std::string & typeId)243 void UnifiedDataHelper::ProcessTypeId(const ValueType &value, std::string &typeId)
244 {
245     if (!std::holds_alternative<std::shared_ptr<Object>>(value)) {
246         return;
247     }
248     auto object = std::get<std::shared_ptr<Object>>(value);
249     if (object->value_.find(UNIFORM_DATA_TYPE) == object->value_.end()) {
250         return;
251     }
252     if (object->value_.find(APPLICATION_DEFINED_RECORD_MARK) != object->value_.end()) {
253         typeId = UtdUtils::GetUtdIdFromUtdEnum(APPLICATION_DEFINED_RECORD);
254     } else if (std::get<std::string>(object->value_[UNIFORM_DATA_TYPE]) == GENERAL_FILE_URI &&
255         object->value_.find(FILE_TYPE) != object->value_.end()) {
256         std::string fileType = std::get<std::string>(object->value_[FILE_TYPE]);
257         if (!fileType.empty()) {
258             typeId = fileType;
259         }
260     }
261 }
262 
CalRecordSummary(std::map<std::string,ValueType> & entry,Summary & summary)263 void UnifiedDataHelper::CalRecordSummary(std::map<std::string, ValueType> &entry, Summary &summary)
264 {
265     for (const auto &[utdId, value] : entry) {
266         auto typeId = utdId;
267         auto valueSize = ObjectUtils::GetValueSize(value, false);
268         ProcessTypeId(value, typeId);
269         auto it = summary.summary.find(typeId);
270         if (it == summary.summary.end()) {
271             summary.summary[typeId] = valueSize;
272         } else {
273             summary.summary[typeId] += valueSize;
274         }
275         summary.totalSize += valueSize;
276     }
277 }
278 
279 } // namespace UDMF
280 } // namespace OHOS