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 "form_provider_data.h"
17
18 #include <cinttypes>
19 #include <fstream>
20 #include <iostream>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "fms_log_wrapper.h"
25 #include "form_constants.h"
26 #include "message_parcel.h"
27 #include "string_ex.h"
28
29 #include <sys/mman.h>
30 #include "ashmem.h"
31 #include "buffer_handle_parcel.h"
32 #include "ipc_file_descriptor.h"
33
34 namespace OHOS {
35 namespace AppExecFwk {
36 const std::string JSON_EMPTY_STRING = "{}";
37 const std::string JSON_IMAGES_STRING = "formImages";
38 constexpr int32_t READ_PARCEL_MAX_IMAGE_DATA_NUM_SIZE = 1000;
39 constexpr int32_t MAX_IMAGE_BYTE_SIZE = 50 * 1024 * 1024;
40 constexpr int32_t MAX_BUFFER_SIZE = 32 * 1024 * 1024;
41 constexpr int32_t BIG_DATA = 32 * 1024;
42 constexpr int32_t SHARE_MEM_ALLOC = 2;
43 /**
44 * @brief Constructor.
45 */
FormProviderData()46 FormProviderData::FormProviderData()
47 {
48 jsonFormProviderData_.clear();
49 }
50
51 /**
52 * @brief A constructor used to create a {@code FormProviderData} instance with data of
53 * the {@code nlohmann::json} type specified.
54 * @param jsonData Indicates the data to be carried in the new {@code FormProviderData} instance,
55 * in {@code nlohmann::json} format.
56 */
FormProviderData(nlohmann::json & jsonData)57 FormProviderData::FormProviderData(nlohmann::json &jsonData)
58 {
59 if (!jsonData.is_object()) {
60 HILOG_ERROR("jsonData not object");
61 return;
62 }
63 jsonFormProviderData_ = jsonData;
64 ParseImagesData();
65 }
66
67 /**
68 * @brief A constructor used to create a {@code FormProviderData} instance with data of the {@code String} type
69 * specified.
70 * @param jsonDataString Indicates the data to be carried in the new {@code FormProviderData} instance,
71 * in JSON string format.
72 */
FormProviderData(std::string jsonDataString)73 FormProviderData::FormProviderData(std::string jsonDataString)
74 {
75 SetDataString(jsonDataString);
76 ParseImagesData();
77 }
78
79 /**
80 * @brief A constructor used to create a {@code FormProviderData} instance with data of the {@code String} type
81 * specified.
82 * @param jsonDataString Indicates the data to be carried in the new {@code FormProviderData} instance, in JSON
83 * string format.
84 * @param isUsedInFRS Indicates is used in frs
85 */
FormProviderData(std::string jsonDataString,bool isUsedInFRS)86 FormProviderData::FormProviderData(std::string jsonDataString, bool isUsedInFRS)
87 {
88 SetDataString(jsonDataString);
89 if (!isUsedInFRS) {
90 ParseImagesData();
91 }
92 }
93
94 /**
95 * @brief Updates form data in this {@code FormProviderData} object.
96 * @param jsonData Indicates the new data to use, in {@code ZSONObject} format.
97 */
UpdateData(nlohmann::json & jsonData)98 void FormProviderData::UpdateData(nlohmann::json &jsonData)
99 {
100 jsonFormProviderData_ = jsonData;
101 }
102 /**
103 * @brief Obtains the form data stored in this {@code FormProviderData} object.
104 * @return Returns json data
105 */
GetData() const106 nlohmann::json FormProviderData::GetData() const
107 {
108 return jsonFormProviderData_;
109 }
110 /**
111 * @brief Obtains the form data stored in this {@code FormProviderData} object.
112 * @return Returns json string format
113 */
GetDataString() const114 std::string FormProviderData::GetDataString() const
115 {
116 HILOG_DEBUG("get data string");
117 std::string dataStr = jsonFormProviderData_.empty() ? "" : jsonFormProviderData_.dump();
118 HILOG_DEBUG("data: %{private}s", dataStr.c_str());
119 return dataStr;
120 }
121
122 /**
123 * @brief Adds an image to this {@code FormProviderData} instance.
124 * @param picName Indicates the name of the image to add.
125 * @param data Indicates the binary data of the image content.
126 */
AddImageData(const std::string & picName,const std::shared_ptr<char> & data,int32_t size)127 void FormProviderData::AddImageData(const std::string &picName, const std::shared_ptr<char> &data, int32_t size)
128 {
129 if ((picName.length() == 0) || (!data)) {
130 HILOG_ERROR("null inputParam");
131 return;
132 }
133
134 rawImageBytesMap_[picName] = std::make_pair(data, size);
135
136 imageDataState_ = IMAGE_DATA_STATE_ADDED;
137 }
138
139 /**
140 * @brief Adds an image to this {@code FormProviderData} instance.
141 * @param picName Indicates the name of the image to add.
142 * @param data Indicates the binary data of the image content.
143 */
AddImageData(const std::string & picName,int fd)144 void FormProviderData::AddImageData(const std::string &picName, int fd)
145 {
146 HILOG_BRIEF("fd is %{public}d", fd);
147 if (fd < 0) {
148 HILOG_ERROR("invalid fd");
149 return;
150 }
151
152 int32_t size = lseek(fd, 0L, SEEK_END);
153 if (size <= 0) {
154 HILOG_ERROR("Get file size failed, errno is %{public}d", errno);
155 return;
156 }
157 HILOG_BRIEF("File size is %{public}d", size);
158 if (lseek(fd, 0L, SEEK_SET) == -1) {
159 return;
160 }
161 if (size > MAX_IMAGE_BYTE_SIZE) {
162 HILOG_ERROR("File is too large");
163 return;
164 }
165 char* bytes = new (std::nothrow) char[size];
166 if (bytes == nullptr) {
167 HILOG_ERROR("malloc memory failed, errno is %{public}d", errno);
168 return;
169 }
170 if (read(fd, bytes, size) < 0) {
171 delete[] bytes;
172 HILOG_ERROR("errno %{public}d", errno);
173 return;
174 }
175 std::shared_ptr<char> data(bytes, DeleteBytes());
176 AddImageData(picName, data, size);
177 }
178
ParseImagesData()179 void FormProviderData::ParseImagesData()
180 {
181 if (jsonFormProviderData_ == nullptr) {
182 HILOG_ERROR("null jsonFormProviderData_");
183 return;
184 }
185 if (!jsonFormProviderData_.contains(JSON_IMAGES_STRING)) {
186 return;
187 }
188 nlohmann::json jsonImages = jsonFormProviderData_.at(JSON_IMAGES_STRING);
189 for (auto iter = jsonImages.begin(); iter != jsonImages.end(); iter++) {
190 if (iter->is_number_integer()) {
191 AddImageData(iter.key(), iter.value());
192 } else {
193 HILOG_ERROR("fd not integer");
194 }
195 }
196 }
197
198 /**
199 * @brief Removes data of an image with the specified {@code picName} from this {@code FormProviderData} instance.
200 * @param picName Indicates the name of the image to remove.
201 */
RemoveImageData(std::string picName)202 void FormProviderData::RemoveImageData(std::string picName)
203 {
204 rawImageBytesMap_.erase(picName);
205 }
206
207 /**
208 * @brief Set the form data stored from string string.
209 * @param Returns string string.
210 */
SetDataString(std::string & jsonDataString)211 void FormProviderData::SetDataString(std::string &jsonDataString)
212 {
213 if (jsonDataString.empty()) {
214 jsonDataString = JSON_EMPTY_STRING;
215 }
216 nlohmann::json jsonObject = nlohmann::json::parse(jsonDataString, nullptr, false);
217 if (jsonObject.is_discarded()) {
218 HILOG_ERROR("fail parse jsonDataString: %{private}s.", jsonDataString.c_str());
219 return;
220 }
221 if (!jsonObject.is_object()) {
222 HILOG_ERROR("jsonDataString not object");
223 return;
224 }
225 jsonFormProviderData_ = jsonObject;
226 }
227 /**
228 * @brief Merge new data to FormProviderData.
229 * @param addJsonData data to merge to FormProviderData
230 */
MergeData(nlohmann::json & addJsonData)231 void FormProviderData::MergeData(nlohmann::json &addJsonData)
232 {
233 HILOG_DEBUG("merge data");
234 if (addJsonData.empty()) {
235 return;
236 }
237
238 if (jsonFormProviderData_.empty()) {
239 jsonFormProviderData_ = addJsonData;
240 return;
241 }
242
243 for (auto && [key, value] : addJsonData.items()) {
244 jsonFormProviderData_[key] = value;
245 }
246 }
247
248 /**
249 * @brief Obtains the imageDataMap stored in this {@code FormProviderData} object.
250 * @return Returns the map that contains shared image data.
251 */
GetImageDataMap() const252 std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> FormProviderData::GetImageDataMap() const
253 {
254 return imageDataMap_;
255 }
256
257 /**
258 * @brief Obtains the add/remove state stored in this {@code FormProviderData} object.
259 * @return Returns the add/remove state of shared image data.
260 */
GetImageDataState() const261 int32_t FormProviderData::GetImageDataState() const
262 {
263 return imageDataState_;
264 }
265
266 /**
267 * @brief Updates imageDataState in this {@code FormProviderData} object.
268 * @param imageDataState Indicates the imageDataState to update.
269 */
SetImageDataState(int32_t imageDataState)270 void FormProviderData::SetImageDataState(int32_t imageDataState)
271 {
272 imageDataState_ = imageDataState;
273 }
274
275 /**
276 * @brief Updates imageDataMap in this {@code FormProviderData} object.
277 * @param imageDataMap Indicates the imageDataMap to update.
278 */
SetImageDataMap(std::map<std::string,std::pair<sptr<FormAshmem>,int32_t>> imageDataMap)279 void FormProviderData::SetImageDataMap(std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> imageDataMap)
280 {
281 imageDataMap_ = imageDataMap;
282 if (!imageDataMap.empty()) {
283 imageDataState_ = IMAGE_DATA_STATE_ADDED;
284 } else {
285 imageDataState_ = IMAGE_DATA_STATE_NO_OPERATION;
286 }
287 }
288
289 /**
290 * Read this {@code FormProviderData} object from a Parcel.
291 * @param parcel the parcel
292 * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise.
293 */
ReadFromParcel(Parcel & parcel)294 bool FormProviderData::ReadFromParcel(Parcel &parcel)
295 {
296 int32_t formDataLength = parcel.ReadInt32();
297 HILOG_DEBUG("ReadFromParcel data length is %{public}d ", formDataLength);
298 std::string jsonDataString;
299 if (formDataLength > BIG_DATA) {
300 void *rawData = ReadAshmemDataFromParcel(parcel, formDataLength);
301 if (rawData == nullptr) {
302 HILOG_INFO("rawData is nullptr");
303 return false;
304 }
305 jsonDataString = std::string(static_cast<const char*>(rawData), formDataLength);
306 free(rawData);
307 rawData = nullptr;
308 } else {
309 jsonDataString = Str16ToStr8(parcel.ReadString16());
310 }
311 nlohmann::json jsonObject = nlohmann::json::parse(jsonDataString, nullptr, false);
312 if (jsonObject.is_discarded()) {
313 HILOG_ERROR("fail parse jsonDataString: %{private}s.", jsonDataString.c_str());
314 return false;
315 }
316 jsonFormProviderData_ = jsonObject;
317
318 imageDataState_ = parcel.ReadInt32();
319 HILOG_DEBUG("imageDateState is %{public}d", imageDataState_);
320 switch (imageDataState_) {
321 case IMAGE_DATA_STATE_ADDED: {
322 if (!HandleImageDataStateAdded(parcel)) {
323 return false;
324 }
325 break;
326 }
327 case IMAGE_DATA_STATE_NO_OPERATION:
328 case IMAGE_DATA_STATE_REMOVED:
329 break;
330 default:
331 HILOG_WARN("unexpected imageDataState_ %{public}d", imageDataState_);
332 break;
333 }
334 return true;
335 }
336
ReadFileDescriptor(Parcel & parcel)337 int FormProviderData::ReadFileDescriptor(Parcel &parcel)
338 {
339 sptr<IPCFileDescriptor> descriptor = parcel.ReadObject<IPCFileDescriptor>();
340 if (descriptor == nullptr) {
341 HILOG_INFO("ReadFileDescriptor get descriptor failed");
342 return -1;
343 }
344 int fd = descriptor->GetFd();
345 if (fd < 0) {
346 HILOG_INFO("ReadFileDescriptor get fd failed, fd:[%{public}d].", fd);
347 return -1;
348 }
349 return dup(fd);
350 }
351
ReleaseMemory(int32_t allocType,void * addr,void * context,uint32_t size)352 void FormProviderData::ReleaseMemory(int32_t allocType, void *addr, void *context, uint32_t size)
353 {
354 if (allocType == SHARE_MEM_ALLOC) {
355 if (context != nullptr) {
356 int *fd = static_cast<int *>(context);
357 if (addr != nullptr) {
358 ::munmap(addr, size);
359 }
360 if (fd != nullptr) {
361 ::close(*fd);
362 }
363 context = nullptr;
364 addr = nullptr;
365 }
366 }
367 }
368
ReadAshmemDataFromParcel(Parcel & parcel,int32_t bufferSize)369 char *FormProviderData::ReadAshmemDataFromParcel(Parcel &parcel, int32_t bufferSize)
370 {
371 char *base = nullptr;
372 int fd = ReadFileDescriptor(parcel);
373 if (!CheckAshmemSize(fd, bufferSize)) {
374 HILOG_INFO("ReadAshmemDataFromParcel check ashmem size failed, fd:[%{public}d].", fd);
375 return nullptr;
376 }
377 if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) {
378 HILOG_INFO("malloc parameter bufferSize:[%{public}d] error.", bufferSize);
379 return nullptr;
380 }
381
382 void *ptr = ::mmap(nullptr, bufferSize, PROT_READ, MAP_SHARED, fd, 0);
383 if (ptr == MAP_FAILED) {
384 // do not close fd here. fd will be closed in FileDescriptor, ::close(fd)
385 HILOG_INFO("ReadImageData map failed, errno:%{public}d", errno);
386 return nullptr;
387 }
388
389 base = static_cast<char *>(malloc(bufferSize));
390 if (base == nullptr) {
391 ::munmap(ptr, bufferSize);
392 HILOG_INFO("alloc output pixel memory size:[%{public}d] error.", bufferSize);
393 return nullptr;
394 }
395 if (memcpy_s(base, bufferSize, ptr, bufferSize) != 0) {
396 ::munmap(ptr, bufferSize);
397 free(base);
398 base = nullptr;
399 HILOG_INFO("memcpy pixel data size:[%{public}d] error.", bufferSize);
400 return nullptr;
401 }
402
403 ReleaseMemory(SHARE_MEM_ALLOC, ptr, &fd, bufferSize);
404 return base;
405 }
406
HandleImageDataStateAdded(Parcel & parcel)407 bool FormProviderData::HandleImageDataStateAdded(Parcel &parcel)
408 {
409 int32_t imageDataNum = parcel.ReadInt32();
410 if (imageDataNum > READ_PARCEL_MAX_IMAGE_DATA_NUM_SIZE) {
411 return false;
412 }
413 HILOG_INFO("imageDataNum is %{public}d", imageDataNum);
414 for (int32_t i = 0; i < imageDataNum; i++) {
415 sptr<FormAshmem> formAshmem = parcel.ReadParcelable<FormAshmem>();
416 if (formAshmem == nullptr) {
417 HILOG_ERROR("null ashmem");
418 return false;
419 }
420 int32_t len = parcel.ReadInt32();
421 std::pair<sptr<FormAshmem>, int32_t> imageDataRecord = std::make_pair(formAshmem, len);
422 auto picName = Str16ToStr8(parcel.ReadString16());
423 imageDataMap_[picName] = imageDataRecord;
424 }
425 return true;
426 }
427
WriteFileDescriptor(Parcel & parcel,int fd) const428 bool FormProviderData::WriteFileDescriptor(Parcel &parcel, int fd) const
429 {
430 if (fd < 0) {
431 HILOG_INFO("WriteFileDescriptor get fd failed, fd:[%{public}d].", fd);
432 return false;
433 }
434 int dupFd = dup(fd);
435 if (dupFd < 0) {
436 HILOG_INFO("WriteFileDescriptor dup fd failed, dupFd:[%{public}d].", dupFd);
437 return false;
438 }
439 sptr<IPCFileDescriptor> descriptor = new IPCFileDescriptor(dupFd);
440 return parcel.WriteObject<IPCFileDescriptor>(descriptor);
441 }
442
WriteAshmemDataToParcel(Parcel & parcel,size_t size,const char * dataPtr) const443 bool FormProviderData::WriteAshmemDataToParcel(Parcel &parcel, size_t size, const char* dataPtr) const
444 {
445 const char *data = dataPtr;
446 std::string name = "formAshmemData";
447 int fd = AshmemCreate(name.c_str(), size);
448 HILOG_INFO("AshmemCreate:[%{public}d].", fd);
449 if (fd < 0) {
450 return false;
451 }
452
453 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
454 HILOG_INFO("AshmemSetProt:[%{public}d].", result);
455 if (result < 0) {
456 ::close(fd);
457 return false;
458 }
459 void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
460 if (ptr == MAP_FAILED) {
461 ::close(fd);
462 HILOG_INFO("WriteAshmemData map failed, errno:%{public}d", errno);
463 return false;
464 }
465 HILOG_INFO("mmap success");
466
467 if (memcpy_s(ptr, size, data, size) != EOK) {
468 ::munmap(ptr, size);
469 ::close(fd);
470 HILOG_INFO("WriteAshmemData memcpy_s error");
471 return false;
472 }
473
474 if (!FormProviderData::WriteFileDescriptor(parcel, fd)) {
475 ::munmap(ptr, size);
476 ::close(fd);
477 HILOG_INFO("WriteAshmemData WriteFileDescriptor error");
478 return false;
479 }
480 HILOG_INFO("WriteAshmemData WriteFileDescriptor success");
481 ::munmap(ptr, size);
482 ::close(fd);
483 return true;
484 }
485
WriteFormData(Parcel & parcel) const486 bool FormProviderData::WriteFormData(Parcel &parcel) const
487 {
488 std::string formData = jsonFormProviderData_.empty() ?
489 JSON_EMPTY_STRING : jsonFormProviderData_.dump();
490 int32_t formDataLength = static_cast<int32_t>(formData.length());
491 parcel.WriteInt32(formDataLength);
492 if (formDataLength > BIG_DATA) {
493 const char* dataPtr = formData.c_str();
494 HILOG_INFO("FormProviderData::WriteFormData data length is %{public}d", formDataLength);
495 return WriteAshmemDataToParcel(parcel, formDataLength, dataPtr);
496 } else {
497 return parcel.WriteString16(Str8ToStr16(formData));
498 }
499 }
500
501 /**
502 * @brief Marshals this {@code FormProviderData} object into a {@link ohos.utils.Parcel} object.
503 * @param parcel Indicates the {@code Parcel} object for marshalling.
504 * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise.
505 */
Marshalling(Parcel & parcel) const506 bool FormProviderData::Marshalling(Parcel &parcel) const
507 {
508 HILOG_DEBUG("jsonFormProviderData_ is private");
509 if (!WriteFormData(parcel)) {
510 return false;
511 }
512
513 parcel.WriteInt32(imageDataState_);
514 HILOG_DEBUG("imageDateState is %{public}d", imageDataState_);
515 switch (imageDataState_) {
516 case IMAGE_DATA_STATE_ADDED: {
517 parcel.WriteInt32(rawImageBytesMap_.size()); // firstly write the number of shared image to add
518 for (auto &entry : rawImageBytesMap_) {
519 if (!WriteImageDataToParcel(parcel, entry.first, entry.second.first, entry.second.second)) {
520 HILOG_ERROR("the picture name is %{public}s", entry.first.c_str());
521 return false;
522 }
523 parcel.WriteInt32(sizeof(entry.second));
524 parcel.WriteString16(Str8ToStr16(entry.first));
525 }
526 break;
527 }
528 case IMAGE_DATA_STATE_NO_OPERATION:
529 case IMAGE_DATA_STATE_REMOVED:
530 break;
531 default:
532 HILOG_WARN("unexpected imageDataState_ %{public}d", imageDataState_);
533 break;
534 }
535 return true;
536 }
537
538 /**
539 * @brief Unmarshals this {@code FormProviderData} object from a {@link ohos.utils.Parcel} object.
540 * @param parcel Indicates the {@code Parcel} object for unmarshalling.
541 * @return FormProviderData.
542 */
Unmarshalling(Parcel & parcel)543 FormProviderData* FormProviderData::Unmarshalling(Parcel &parcel)
544 {
545 std::unique_ptr<FormProviderData> formProviderData = std::make_unique<FormProviderData>();
546 if (formProviderData && !formProviderData->ReadFromParcel(parcel)) {
547 formProviderData = nullptr;
548 }
549 return formProviderData.release();
550 }
551
552 /**
553 * @brief Clear imageDataMap, rawImageBytesMap_, imageDataState_ and jsonFormProviderData_.
554 */
ClearData()555 void FormProviderData::ClearData()
556 {
557 jsonFormProviderData_.clear();
558 }
559
NeedCache() const560 bool FormProviderData::NeedCache() const
561 {
562 return !jsonFormProviderData_.empty() || !imageDataMap_.empty();
563 }
564
WriteImageDataToParcel(Parcel & parcel,const std::string & picName,const std::shared_ptr<char> & data,int32_t size) const565 bool FormProviderData::WriteImageDataToParcel(Parcel &parcel, const std::string &picName,
566 const std::shared_ptr<char> &data, int32_t size) const
567 {
568 FormAshmem formAshmem;
569 if (!formAshmem.WriteToAshmem(picName, data.get(), size)) {
570 return false;
571 }
572
573 // write formAshmem
574 if (!parcel.WriteParcelable(&formAshmem)) {
575 HILOG_ERROR("write FormAshmem fail,the picture name is %{public}s", picName.c_str());
576 return false;
577 }
578
579 return true;
580 }
581
ConvertRawImageData()582 bool FormProviderData::ConvertRawImageData()
583 {
584 HILOG_INFO("call");
585 for (auto &entry : rawImageBytesMap_) {
586 sptr<FormAshmem> formAshmem = new (std::nothrow) FormAshmem();
587 if (formAshmem == nullptr) {
588 HILOG_ERROR("alloc shmem failed");
589 return false;
590 }
591 if (!formAshmem->WriteToAshmem(entry.first, entry.second.first.get(), entry.second.second)) {
592 HILOG_ERROR("write to shmem failed");
593 return false;
594 }
595 std::pair<sptr<FormAshmem>, int32_t> imageDataRecord = std::make_pair(formAshmem, entry.second.second);
596 imageDataMap_[entry.first] = imageDataRecord;
597 }
598 rawImageBytesMap_.clear();
599 HILOG_INFO("end");
600 return true;
601 }
602 } // namespace AppExecFwk
603 } // namespace OHOS
604