1 /*
2 * Copyright (c) 2025 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 "message_parcel_warp.h"
17
18 #include <sys/mman.h>
19 #include <sys/syscall.h>
20 #include <unistd.h>
21
22 #include "api/visibility.h"
23 #include "ashmem.h"
24 #include "parameters.h"
25 #include "parcel.h"
26 #include "pasteboard_hilog.h"
27 #include "securec.h"
28
29 namespace OHOS {
30 namespace MiscServices {
31
32 constexpr int64_t SIZE_K = 1024;
33 constexpr int32_t KERNEL_MAX_SIZE = 2048; // 2G
34 constexpr size_t MIN_RAW_SIZE = 32 * 1024; // 32k
35 constexpr int32_t DEFAULT_LOCAL_CAPACITY = 128;
36 constexpr size_t WRITE_SPLIT_CHUNK_SIZE = 256 * 1024 * 1024;
37
MessageParcelWarp()38 MessageParcelWarp::MessageParcelWarp()
39 {
40 writeRawDataFd_ = -1;
41 readRawDataFd_ = -1;
42 kernelMappedWrite_ = nullptr;
43 kernelMappedRead_ = nullptr;
44 rawData_ = nullptr;
45 rawDataSize_ = 0;
46 canWrite_ = true;
47 canRead_ = true;
48 static int32_t paramMaxSize =
49 OHOS::system::GetIntParameter("const.pasteboard.local_data_capacity", DEFAULT_LOCAL_CAPACITY);
50 PASTEBOARD_CHECK_AND_RETURN_LOGE(paramMaxSize >= DEFAULT_LOCAL_CAPACITY && paramMaxSize <= KERNEL_MAX_SIZE,
51 PASTEBOARD_MODULE_COMMON, "invalid param, max_raw_size=%{public}d", paramMaxSize);
52 maxRawDataSize_ = paramMaxSize * SIZE_K * SIZE_K;
53 }
54
~MessageParcelWarp()55 MessageParcelWarp::~MessageParcelWarp()
56 {
57 if (kernelMappedWrite_ != nullptr) {
58 ::munmap(kernelMappedWrite_, rawDataSize_);
59 kernelMappedWrite_ = nullptr;
60 }
61 if (kernelMappedRead_ != nullptr) {
62 ::munmap(kernelMappedRead_, rawDataSize_);
63 kernelMappedRead_ = nullptr;
64 }
65
66 if (readRawDataFd_ >= 0) {
67 ::close(readRawDataFd_);
68 readRawDataFd_ = -1;
69 }
70 if (writeRawDataFd_ >= 0) {
71 ::close(writeRawDataFd_);
72 writeRawDataFd_ = -1;
73 }
74 rawData_ = nullptr;
75 rawDataSize_ = 0;
76 canWrite_ = false;
77 canRead_ = false;
78 }
79
MemcpyData(void * ptr,size_t size,const void * data,size_t count)80 bool MessageParcelWarp::MemcpyData(void *ptr, size_t size, const void *data, size_t count)
81 {
82 if (size <= WRITE_SPLIT_CHUNK_SIZE) {
83 if (memcpy_s(ptr, size, data, count) != EOK) {
84 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_COMMON, "memcpy_s failed, size:%{public}zu", size);
85 return false;
86 }
87 return true;
88 }
89 char* ptrDest = static_cast<char*>(ptr);
90 const char* ptrSrc = static_cast<const char*>(data);
91 size_t remaining = size;
92 size_t offset = 0;
93 while (remaining > 0) {
94 size_t currentChunkSize = (remaining > WRITE_SPLIT_CHUNK_SIZE) ? WRITE_SPLIT_CHUNK_SIZE : remaining;
95 size_t destSize = size - offset;
96 size_t destChunkCount = currentChunkSize;
97 size_t copyCount = (destChunkCount <= destSize) ? destChunkCount : destSize;
98 if (memcpy_s(ptrDest + offset, copyCount, ptrSrc + offset, currentChunkSize) != EOK) {
99 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_COMMON, "memcpy_s failed, size:%{public}zu", size);
100 return false;
101 }
102 offset += currentChunkSize;
103 remaining -= currentChunkSize;
104 }
105 return true;
106 }
107
WriteRawData(MessageParcel & parcelPata,const void * data,size_t size)108 bool MessageParcelWarp::WriteRawData(MessageParcel &parcelPata, const void *data, size_t size)
109 {
110 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(canWrite_, false,
111 PASTEBOARD_MODULE_COMMON, "is already write, size:%{public}zu", size);
112 canWrite_ = false;
113 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(data != nullptr, false, PASTEBOARD_MODULE_COMMON, "data is null");
114 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(0 < size && static_cast<int64_t>(size) <= maxRawDataSize_, false,
115 PASTEBOARD_MODULE_COMMON, "size invalid, size:%{public}zu", size);
116 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(kernelMappedWrite_ == nullptr, false,
117 PASTEBOARD_MODULE_COMMON, "kernelMappedWrite_ not null end.");
118 if (!parcelPata.WriteInt64(size)) {
119 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_COMMON, "data WriteInt64 failed end.");
120 return false;
121 }
122 if (size <= MIN_RAW_SIZE) {
123 rawDataSize_ = size;
124 return parcelPata.WriteUnpadBuffer(data, size);
125 }
126 int fd = AshmemCreate("Pasteboard Ashmem", size);
127 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(fd >= 0, false, PASTEBOARD_MODULE_COMMON, "ashmem create failed");
128
129 writeRawDataFd_ = fd;
130 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
131 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(result >= 0, false, PASTEBOARD_MODULE_COMMON, "ashmem set port failed");
132
133 void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
134 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(ptr != MAP_FAILED, false,
135 PASTEBOARD_MODULE_COMMON, "mmap failed, fd:%{public}d size:%{public}zu", fd, size);
136
137 if (!parcelPata.WriteFileDescriptor(fd)) {
138 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_COMMON, "write file descriptor failed, size:%{public}zu", size);
139 ::munmap(ptr, size);
140 return false;
141 }
142 if (!MemcpyData(ptr, size, data, size)) {
143 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_COMMON, "memcpy_s failed, fd:%{public}d size:%{public}zu", fd, size);
144 ::munmap(ptr, size);
145 return false;
146 }
147 kernelMappedWrite_ = ptr;
148 rawDataSize_ = size;
149 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_COMMON, "write ashmem end. fd:%{public}d size:%{public}zu", fd, size);
150 return true;
151 }
152
ReadRawData(MessageParcel & parcelPata,size_t size)153 const void *MessageParcelWarp::ReadRawData(MessageParcel &parcelPata, size_t size)
154 {
155 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(canRead_, nullptr,
156 PASTEBOARD_MODULE_COMMON, "is already write, size:%{public}zu", size);
157 canRead_ = false;
158 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(0 < size && static_cast<int64_t>(size) <= maxRawDataSize_, nullptr,
159 PASTEBOARD_MODULE_COMMON, "size invalid, size:%{public}zu", size);
160 size_t bufferSize = static_cast<size_t>(parcelPata.ReadInt64());
161 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(bufferSize == size, nullptr, PASTEBOARD_MODULE_COMMON,
162 "buffer size not equal size, bufferSize:%{public}zu size:%{public}zu", bufferSize, size);
163 if (bufferSize <= MIN_RAW_SIZE) {
164 rawDataSize_ = size;
165 return parcelPata.ReadUnpadBuffer(size);
166 }
167
168 int fd = parcelPata.ReadFileDescriptor();
169 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(fd >= 0, nullptr,
170 PASTEBOARD_MODULE_COMMON, "read file descriptor failed fd:%{public}d", fd);
171 readRawDataFd_ = fd;
172
173 void *ptr = ::mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
174 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(ptr != MAP_FAILED, nullptr,
175 PASTEBOARD_MODULE_COMMON, "mmap failed, fd:%{public}d size:%{public}zu", fd, size);
176
177 kernelMappedRead_ = ptr;
178 rawDataSize_ = size;
179 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_COMMON, "read ashmem end. fd:%{public}d size:%{public}zu", fd, size);
180 return ptr;
181 }
182
CreateTmpFd()183 int MessageParcelWarp::CreateTmpFd()
184 {
185 int fd = AshmemCreate("PasteboardTmpAshmem", 1);
186 PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(fd >= 0, -1, PASTEBOARD_MODULE_COMMON, "ashmem create failed");
187 writeRawDataFd_ = fd;
188 return fd;
189 }
190
GetWriteDataFd()191 int MessageParcelWarp::GetWriteDataFd()
192 {
193 return writeRawDataFd_;
194 }
195 }
196 }