• 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 "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