• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (C) 2023 - 2025 Huawei Device Co., Ltd.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef _FILE_INFO_SHARED_MEMORY_H_
18 #define _FILE_INFO_SHARED_MEMORY_H_
19 
20 #include <inttypes.h>
21 #include <stdint.h>
22 #include <string>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include <utility>
26 #include <vector>
27 
28 #include "ashmem.h"
29 #include "file_access_extension_info.h"
30 #include "file_access_framework_errno.h"
31 #include "hilog_wrapper.h"
32 #include "ipc_file_descriptor.h"
33 #include "parcel.h"
34 #include "securec.h"
35 
36 namespace OHOS {
37 namespace FileAccessFwk {
38 namespace {
39     const uint32_t DEFAULT_CAPACITY_200KB = 200 * 1024;
40     const uint32_t MAX_CAPACITY_2MB = 2 * 1024 * 1024;
41 } // namespace
42 
43 class SharedMemoryInfo : public OHOS::Parcelable {
44 public:
45     const char *memName {nullptr};
46     int memFd {-1};
47     uint8_t *memHead {nullptr};
48     uint8_t *memTail {nullptr};
49     uint64_t memSize {0};
50 
51     uint8_t *dataPtr {nullptr};
52     uint64_t dataSize {0};
53     uint32_t dataCounts = 0;
54 
55     bool isOver {false};
56     uint32_t totalDataCounts = 0;
57     uint32_t leftDataCounts = 0;
58 
59     SharedMemoryInfo() = default;
60 
Marshalling(Parcel & parcel)61     bool Marshalling(Parcel &parcel) const override
62     {
63         if (!WriteFileDescriptor(parcel, memFd)) {
64             HILOG_ERROR("WriteFileDescriptor fail");
65             return false;
66         }
67         if (!parcel.WriteUint64(memSize)) {
68             return false;
69         }
70         if (!parcel.WriteUint32(dataCounts)) {
71             return false;
72         }
73         if (!parcel.WriteUint64(dataSize)) {
74             return false;
75         }
76         if (!parcel.WriteUint32(leftDataCounts)) {
77             return false;
78         }
79         if (!parcel.WriteBool(isOver)) {
80             return false;
81         }
82         return true;
83     }
84 
Unmarshalling(Parcel & parcel)85     static SharedMemoryInfo *Unmarshalling(Parcel &parcel)
86     {
87         auto *obj = new (std::nothrow) SharedMemoryInfo();
88         if (obj != nullptr && !obj->ReadFromParcel(parcel)) {
89             delete obj;
90             obj = nullptr;
91         }
92         return obj;
93     }
94 
ReadFromParcel(Parcel & parcel)95     bool ReadFromParcel(Parcel &parcel)
96     {
97         if (!ReadFileDescriptor(parcel)) {
98             return false;
99         }
100 
101         memSize = parcel.ReadUint64();
102         dataCounts = parcel.ReadUint32();
103         dataSize = parcel.ReadUint64();
104         leftDataCounts = parcel.ReadUint32();
105         isOver = parcel.ReadBool();
106         return true;
107     }
108 
Empty()109     bool Empty() const
110     {
111         return dataCounts == 0;
112     }
113 
Size()114     uint32_t Size() const
115     {
116         return dataCounts;
117     }
118 
Clear()119     void Clear()
120     {
121         dataPtr = memHead;
122         dataSize = 0;
123         dataCounts = 0;
124         isOver = false;
125         totalDataCounts = 0;
126         leftDataCounts = 0;
127     }
128 
129 private:
WriteFileDescriptor(Parcel & parcel,int fd)130     bool WriteFileDescriptor(Parcel &parcel, int fd) const
131     {
132         if (fd < 0) {
133             return false;
134         }
135         int dupFd = dup(fd);
136         if (dupFd < 0) {
137             return false;
138         }
139         sptr<IPCFileDescriptor> descriptor = new (std::nothrow)IPCFileDescriptor(dupFd);
140         if (descriptor == nullptr) {
141             HILOG_ERROR("create IPCFileDescriptor object failed");
142             return false;
143         }
144         return parcel.WriteObject<IPCFileDescriptor>(descriptor);
145     }
146 
ReadFileDescriptor(Parcel & parcel)147     bool ReadFileDescriptor(Parcel &parcel)
148     {
149         sptr<IPCFileDescriptor> descriptor = parcel.ReadObject<IPCFileDescriptor>();
150         if (descriptor == nullptr) {
151             return false;
152         }
153         int fd = descriptor->GetFd();
154         if (fd < 0) {
155             return false;
156         }
157         memFd = dup(fd);
158         return true;
159     }
160 };
161 
162 class SharedMemoryOperation {
163 public:
CreateSharedMemory(const char * memName,uint64_t memSize,SharedMemoryInfo & memInfo)164     static int CreateSharedMemory(const char *memName, uint64_t memSize, SharedMemoryInfo &memInfo)
165     {
166         memInfo.memName = memName;
167         memInfo.memSize = memSize;
168         memInfo.memFd = AshmemCreate(memInfo.memName, memInfo.memSize);
169         if (memInfo.memFd < 0) {
170             HILOG_ERROR("Create shared memory error, shared memory name is %{public}s code: %{public}d",
171                     memInfo.memName, memInfo.memFd);
172             return memInfo.memFd;
173         }
174 
175         int ret = AshmemSetProt(memInfo.memFd, PROT_READ | PROT_WRITE);
176         if (ret < 0) {
177             HILOG_ERROR("Set shared memory protection mask error, code: %{public}d", ret);
178             ::close(memInfo.memFd);
179             return ret;
180         }
181 
182         return MapSharedMemory(memInfo);
183     }
184 
ExpandSharedMemory(SharedMemoryInfo & memInfo)185     static int ExpandSharedMemory(SharedMemoryInfo &memInfo)
186     {
187         uint64_t memSize = 0;
188         auto alloc = CalculateMemSize(memSize, memInfo);
189         if (alloc) {
190             DestroySharedMemory(memInfo);
191             int ret = CreateSharedMemory(memInfo.memName, memSize, memInfo);
192             if (ret != ERR_OK) {
193                 HILOG_ERROR("Recreate shared memory error, code: %{public}d", ret);
194                 return ret;
195             }
196             HILOG_INFO("Recreate shared memory success, memory size: %{public}" PRIu64, memSize);
197         }
198         return ERR_OK;
199     }
200 
DestroySharedMemory(SharedMemoryInfo & memInfo)201     static void DestroySharedMemory(SharedMemoryInfo &memInfo)
202     {
203         if (memInfo.memHead != nullptr) {
204             ::munmap(memInfo.memHead, memInfo.memSize);
205             ::close(memInfo.memFd);
206             memInfo.memHead = nullptr;
207         }
208     }
209 
MapSharedMemory(SharedMemoryInfo & memInfo)210     static int MapSharedMemory(SharedMemoryInfo &memInfo)
211     {
212         memInfo.memHead = reinterpret_cast<uint8_t *>(
213             ::mmap(nullptr, memInfo.memSize, PROT_READ | PROT_WRITE, MAP_SHARED, memInfo.memFd, 0));
214         if (memInfo.memHead == MAP_FAILED) {
215             int ret = errno;
216             ::close(memInfo.memFd);
217             HILOG_ERROR("Shared memory map error, code: %{public}d", ret);
218             return ret;
219         }
220         memInfo.memTail = memInfo.memHead + memInfo.memSize;
221         memInfo.dataPtr = memInfo.memHead;
222         memInfo.Clear();
223         return ERR_OK;
224     }
225 
CalculateMemSize(uint64_t & memSize,SharedMemoryInfo & memInfo)226     static bool CalculateMemSize(uint64_t &memSize, SharedMemoryInfo &memInfo)
227     {
228         uint64_t allocSize = ((memInfo.leftDataCounts + memInfo.totalDataCounts - 1) / memInfo.totalDataCounts + 1)
229             * DEFAULT_CAPACITY_200KB;
230 
231         if (allocSize >= MAX_CAPACITY_2MB && memInfo.memSize < MAX_CAPACITY_2MB) {
232             memSize = MAX_CAPACITY_2MB;
233             HILOG_ERROR("memSize: %{public}" PRIu64, memSize);
234             return true;
235         }
236 
237         if (allocSize < MAX_CAPACITY_2MB && memInfo.memSize < MAX_CAPACITY_2MB && memInfo.memSize < allocSize) {
238             memSize = allocSize;
239             HILOG_ERROR("memSize: %{public}" PRIu64, memSize);
240             return true;
241         }
242         return false;
243     }
244 
WriteFileInfos(std::vector<FileInfo> & fileInfoVec,SharedMemoryInfo & memInfo)245     static uint32_t WriteFileInfos(std::vector<FileInfo> &fileInfoVec, SharedMemoryInfo &memInfo)
246     {
247         uint32_t count = 0;
248         for (auto &info : fileInfoVec) {
249             int ret = WriteFileInfo(info, memInfo);
250             if (!ret) {
251                 return count;
252             }
253             count++;
254         }
255         return count;
256     }
257 
WriteFileInfo(FileInfo & info,SharedMemoryInfo & memInfo)258     static bool WriteFileInfo(FileInfo &info, SharedMemoryInfo &memInfo)
259     {
260         uint64_t fileInfoSize = GetFileInfoSize(info);
261         uint64_t leftSize = memInfo.memSize - memInfo.dataSize;
262         if (leftSize < fileInfoSize) {
263             HILOG_INFO("Shared memory cannot hold current data");
264             return false;
265         }
266 
267         uint8_t *dataPtr = memInfo.dataPtr;
268         uint64_t dataSize = memInfo.dataSize;
269         bool ret = WriteString(info.uri, memInfo);
270         ret = ret && WriteString(info.relativePath, memInfo);
271         ret = ret && WriteString(info.fileName, memInfo);
272         ret = ret && WriteInt32(info.mode, memInfo);
273         ret = ret && WriteInt64(info.size, memInfo);
274         ret = ret && WriteInt64(info.mtime, memInfo);
275         ret = ret && WriteString(info.mimeType, memInfo);
276         if (!ret) {
277             memInfo.dataPtr = dataPtr;
278             memInfo.dataSize = dataSize;
279             HILOG_ERROR("Write FileInfo into shared memmory failed");
280             return false;
281         }
282         memInfo.dataCounts++;
283         return true;
284     }
285 
ReadFileInfo(FileInfo & info,SharedMemoryInfo & memInfo)286     static bool ReadFileInfo(FileInfo &info, SharedMemoryInfo &memInfo)
287     {
288         if (memInfo.dataCounts == 0) {
289             HILOG_INFO("No data in shared memory");
290             return false;
291         }
292         uint8_t *dataPtr = memInfo.dataPtr;
293         uint64_t dataSize = memInfo.dataSize;
294         bool ret = ReadString(info.uri, memInfo);
295         ret = ret && ReadString(info.relativePath, memInfo);
296         ret = ret && ReadString(info.fileName, memInfo);
297         ret = ret && ReadInt32(info.mode, memInfo);
298         ret = ret && ReadInt64(info.size, memInfo);
299         ret = ret && ReadInt64(info.mtime, memInfo);
300         ret = ret && ReadString(info.mimeType, memInfo);
301         if (!ret) {
302             memInfo.dataPtr = dataPtr;
303             memInfo.dataSize = dataSize;
304             return false;
305         }
306         memInfo.dataCounts--;
307         return true;
308     }
309 
310 private:
311     template <typename T>
WriteInteger(T & integer,SharedMemoryInfo & memInfo)312     static bool WriteInteger(T &integer, SharedMemoryInfo &memInfo)
313     {
314         uint8_t *src = reinterpret_cast<uint8_t *>(&integer);
315         uint8_t *dest = memInfo.dataPtr;
316         if (memcpy_s(dest, sizeof(T), src, sizeof(T)) != ERR_OK) {
317             HILOG_ERROR("WriteInteger failed:%{public}s", std::strerror(errno));
318             return false;
319         }
320         memInfo.dataPtr += sizeof(T);
321         memInfo.dataSize += sizeof(T);
322         return true;
323     }
324 
325     template <typename T>
ReadInteger(T & integer,SharedMemoryInfo & memInfo)326     static bool ReadInteger(T &integer, SharedMemoryInfo &memInfo)
327     {
328         uint8_t *src = memInfo.dataPtr;
329         uint8_t *dest = reinterpret_cast<uint8_t *>(&integer);
330         if (memcpy_s(dest, sizeof(T), src, sizeof(T)) != ERR_OK) {
331             HILOG_ERROR("ReadInteger failed:%{public}s", std::strerror(errno));
332             return false;
333         }
334         memInfo.dataPtr += sizeof(T);
335         memInfo.dataSize -= sizeof(T);
336         return true;
337     }
338 
WriteInt32(int32_t & value,SharedMemoryInfo & memInfo)339     static bool WriteInt32(int32_t &value, SharedMemoryInfo &memInfo)
340     {
341         return WriteInteger<int32_t>(value, memInfo);
342     }
343 
WriteInt64(int64_t & value,SharedMemoryInfo & memInfo)344     static bool WriteInt64(int64_t &value, SharedMemoryInfo &memInfo)
345     {
346         return WriteInteger<int64_t>(value, memInfo);
347     }
348 
ReadInt32(int32_t & value,SharedMemoryInfo & memInfo)349     static bool ReadInt32(int32_t &value, SharedMemoryInfo &memInfo)
350     {
351         return ReadInteger<int32_t>(value, memInfo);
352     }
353 
ReadInt64(int64_t & value,SharedMemoryInfo & memInfo)354     static bool ReadInt64(int64_t &value, SharedMemoryInfo &memInfo)
355     {
356         return ReadInteger<int64_t>(value, memInfo);
357     }
358 
WriteString(std::string & inVal,SharedMemoryInfo & memInfo)359     static bool WriteString(std::string &inVal, SharedMemoryInfo &memInfo)
360     {
361         std::string::size_type len = inVal.size();
362         bool ret = WriteInteger<std::string::size_type>(len, memInfo);
363         if (!ret) {
364             return false;
365         }
366         if (len == 0) {
367             return true;
368         }
369 
370         const uint8_t *src = reinterpret_cast<const uint8_t *>(inVal.c_str());
371         uint8_t *dest = memInfo.dataPtr;
372         if (memcpy_s(dest, len, src, len) != ERR_OK) {
373             HILOG_ERROR("WriteString failed:%{public}s", std::strerror(errno));
374             return false;
375         }
376         memInfo.dataPtr += len;
377         memInfo.dataSize += len;
378         return true;
379     }
380 
ReadString(std::string & outVal,SharedMemoryInfo & memInfo)381     static bool ReadString(std::string &outVal, SharedMemoryInfo &memInfo)
382     {
383         std::string::size_type len = 0;
384         int ret = ReadInteger<std::string::size_type>(len, memInfo);
385         if (!ret) {
386             return false;
387         }
388         if (len == 0) {
389             outVal = "";
390             return true;
391         }
392 
393         uint8_t *src = memInfo.dataPtr;
394         uint8_t dest[len + 1];
395         if (memcpy_s(dest, len, src, len) != ERR_OK) {
396             HILOG_ERROR("ReadString failed:%{public}s", std::strerror(errno));
397             return false;
398         }
399         dest[len] = 0;
400         outVal = reinterpret_cast<char *>(dest);
401         memInfo.dataPtr += len;
402         memInfo.dataSize -= len;
403         return true;
404     }
405 
GetFileInfoSize(FileInfo & info)406     static uint64_t GetFileInfoSize(FileInfo &info)
407     {
408         return sizeof(std::string::size_type) + info.uri.size() + sizeof(std::string::size_type) +
409             info.relativePath.size() + sizeof(std::string::size_type) + info.fileName.size() + sizeof(info.mode) +
410             sizeof(info.size) + sizeof(info.mtime) + sizeof(std::string::size_type) + info.mimeType.size();
411     }
412 };
413 } // namespace FileAccessFwk
414 } // namespace OHOS
415 #endif // _FILE_INFO_SHARED_MEMORY_H_
416