1 
2 /*
3  * Copyright (C) 2023 - 2024 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     SharedMemoryInfo(const SharedMemoryInfo &) = delete;
61     SharedMemoryInfo &operator=(SharedMemoryInfo &) = delete;
62 
Marshalling(Parcel & parcel)63     bool Marshalling(Parcel &parcel) const override
64     {
65         if (!WriteFileDescriptor(parcel, memFd)) {
66             HILOG_ERROR("WriteFileDescriptor fail");
67             return false;
68         }
69         if (!parcel.WriteUint64(memSize)) {
70             return false;
71         }
72         return true;
73     }
74 
Unmarshalling(Parcel & parcel)75     static SharedMemoryInfo *Unmarshalling(Parcel &parcel)
76     {
77         auto *obj = new (std::nothrow) SharedMemoryInfo();
78         if (obj != nullptr && !obj->ReadFromParcel(parcel)) {
79             delete obj;
80             obj = nullptr;
81         }
82         return obj;
83     }
84 
ReadFromParcel(Parcel & parcel)85     bool ReadFromParcel(Parcel &parcel)
86     {
87         if (!ReadFileDescriptor(parcel)) {
88             return false;
89         }
90 
91         memSize = parcel.ReadUint64();
92         return true;
93     }
94 
Empty()95     bool Empty() const
96     {
97         return dataCounts == 0;
98     }
99 
Size()100     uint32_t Size() const
101     {
102         return dataCounts;
103     }
104 
Clear()105     void Clear()
106     {
107         dataPtr = memHead;
108         dataSize = 0;
109         dataCounts = 0;
110         isOver = false;
111         totalDataCounts = 0;
112         leftDataCounts = 0;
113     }
114 
115 private:
WriteFileDescriptor(Parcel & parcel,int fd)116     bool WriteFileDescriptor(Parcel &parcel, int fd) const
117     {
118         if (fd < 0) {
119             return false;
120         }
121         int dupFd = dup(fd);
122         if (dupFd < 0) {
123             return false;
124         }
125         sptr<IPCFileDescriptor> descriptor = new (std::nothrow)IPCFileDescriptor(dupFd);
126         if (descriptor == nullptr) {
127             HILOG_ERROR("create IPCFileDescriptor object failed");
128             return false;
129         }
130         return parcel.WriteObject<IPCFileDescriptor>(descriptor);
131     }
132 
ReadFileDescriptor(Parcel & parcel)133     bool ReadFileDescriptor(Parcel &parcel)
134     {
135         sptr<IPCFileDescriptor> descriptor = parcel.ReadObject<IPCFileDescriptor>();
136         if (descriptor == nullptr) {
137             return false;
138         }
139         int fd = descriptor->GetFd();
140         if (fd < 0) {
141             return false;
142         }
143         memFd = dup(fd);
144         return true;
145     }
146 };
147 
148 class SharedMemoryOperation {
149 public:
CreateSharedMemory(const char * memName,uint64_t memSize,SharedMemoryInfo & memInfo)150     static int CreateSharedMemory(const char *memName, uint64_t memSize, SharedMemoryInfo &memInfo)
151     {
152         memInfo.memName = memName;
153         memInfo.memSize = memSize;
154         memInfo.memFd = AshmemCreate(memInfo.memName, memInfo.memSize);
155         if (memInfo.memFd < 0) {
156             HILOG_ERROR("Create shared memory error, shared memory name is %{public}s code: %{public}d",
157                     memInfo.memName, memInfo.memFd);
158             return memInfo.memFd;
159         }
160 
161         int ret = AshmemSetProt(memInfo.memFd, PROT_READ | PROT_WRITE);
162         if (ret < 0) {
163             HILOG_ERROR("Set shared memory protection mask error, code: %{public}d", ret);
164             ::close(memInfo.memFd);
165             return ret;
166         }
167 
168         return MapSharedMemory(memInfo);
169     }
170 
ExpandSharedMemory(SharedMemoryInfo & memInfo)171     static int ExpandSharedMemory(SharedMemoryInfo &memInfo)
172     {
173         uint64_t memSize = 0;
174         auto alloc = CalculateMemSize(memSize, memInfo);
175         if (alloc) {
176             DestroySharedMemory(memInfo);
177             int ret = CreateSharedMemory(memInfo.memName, memSize, memInfo);
178             if (ret != ERR_OK) {
179                 HILOG_ERROR("Recreate shared memory error, code: %{public}d", ret);
180                 return ret;
181             }
182             HILOG_INFO("Recreate shared memory success, memory size: %{public}" PRIu64, memSize);
183         }
184         return ERR_OK;
185     }
186 
DestroySharedMemory(SharedMemoryInfo & memInfo)187     static void DestroySharedMemory(SharedMemoryInfo &memInfo)
188     {
189         if (memInfo.memHead != nullptr) {
190             ::munmap(memInfo.memHead, memInfo.memSize);
191             ::close(memInfo.memFd);
192             memInfo.memHead = nullptr;
193         }
194     }
195 
MapSharedMemory(SharedMemoryInfo & memInfo)196     static int MapSharedMemory(SharedMemoryInfo &memInfo)
197     {
198         memInfo.memHead = reinterpret_cast<uint8_t *>(
199             ::mmap(nullptr, memInfo.memSize, PROT_READ | PROT_WRITE, MAP_SHARED, memInfo.memFd, 0));
200         if (memInfo.memHead == MAP_FAILED) {
201             int ret = errno;
202             ::close(memInfo.memFd);
203             HILOG_ERROR("Shared memory map error, code: %{public}d", ret);
204             return ret;
205         }
206         memInfo.memTail = memInfo.memHead + memInfo.memSize;
207         memInfo.dataPtr = memInfo.memHead;
208         memInfo.Clear();
209         return ERR_OK;
210     }
211 
CalculateMemSize(uint64_t & memSize,SharedMemoryInfo & memInfo)212     static bool CalculateMemSize(uint64_t &memSize, SharedMemoryInfo &memInfo)
213     {
214         uint64_t allocSize = ((memInfo.leftDataCounts + memInfo.totalDataCounts - 1) / memInfo.totalDataCounts + 1)
215             * DEFAULT_CAPACITY_200KB;
216 
217         if (allocSize >= MAX_CAPACITY_2MB && memInfo.memSize < MAX_CAPACITY_2MB) {
218             memSize = MAX_CAPACITY_2MB;
219             HILOG_ERROR("memSize: %{public}" PRIu64, memSize);
220             return true;
221         }
222 
223         if (allocSize < MAX_CAPACITY_2MB && memInfo.memSize < MAX_CAPACITY_2MB && memInfo.memSize < allocSize) {
224             memSize = allocSize;
225             HILOG_ERROR("memSize: %{public}" PRIu64, memSize);
226             return true;
227         }
228         return false;
229     }
230 
WriteFileInfos(std::vector<FileInfo> & fileInfoVec,SharedMemoryInfo & memInfo)231     static uint32_t WriteFileInfos(std::vector<FileInfo> &fileInfoVec, SharedMemoryInfo &memInfo)
232     {
233         uint32_t count = 0;
234         for (auto &info : fileInfoVec) {
235             int ret = WriteFileInfo(info, memInfo);
236             if (!ret) {
237                 return count;
238             }
239             count++;
240         }
241         return count;
242     }
243 
WriteFileInfo(FileInfo & info,SharedMemoryInfo & memInfo)244     static bool WriteFileInfo(FileInfo &info, SharedMemoryInfo &memInfo)
245     {
246         uint64_t fileInfoSize = GetFileInfoSize(info);
247         uint64_t leftSize = memInfo.memSize - memInfo.dataSize;
248         if (leftSize < fileInfoSize) {
249             HILOG_INFO("Shared memory cannot hold current data");
250             return false;
251         }
252 
253         uint8_t *dataPtr = memInfo.dataPtr;
254         uint64_t dataSize = memInfo.dataSize;
255         bool ret = WriteString(info.uri, memInfo);
256         ret = ret && WriteString(info.relativePath, memInfo);
257         ret = ret && WriteString(info.fileName, memInfo);
258         ret = ret && WriteInt32(info.mode, memInfo);
259         ret = ret && WriteInt64(info.size, memInfo);
260         ret = ret && WriteInt64(info.mtime, memInfo);
261         ret = ret && WriteString(info.mimeType, memInfo);
262         if (!ret) {
263             memInfo.dataPtr = dataPtr;
264             memInfo.dataSize = dataSize;
265             HILOG_ERROR("Write FileInfo into shared memmory failed");
266             return false;
267         }
268         memInfo.dataCounts++;
269         return true;
270     }
271 
ReadFileInfo(FileInfo & info,SharedMemoryInfo & memInfo)272     static bool ReadFileInfo(FileInfo &info, SharedMemoryInfo &memInfo)
273     {
274         if (memInfo.dataCounts == 0) {
275             HILOG_INFO("No data in shared memory");
276             return false;
277         }
278         uint8_t *dataPtr = memInfo.dataPtr;
279         uint64_t dataSize = memInfo.dataSize;
280         bool ret = ReadString(info.uri, memInfo);
281         ret = ret && ReadString(info.relativePath, memInfo);
282         ret = ret && ReadString(info.fileName, memInfo);
283         ret = ret && ReadInt32(info.mode, memInfo);
284         ret = ret && ReadInt64(info.size, memInfo);
285         ret = ret && ReadInt64(info.mtime, memInfo);
286         ret = ret && ReadString(info.mimeType, memInfo);
287         if (!ret) {
288             memInfo.dataPtr = dataPtr;
289             memInfo.dataSize = dataSize;
290             return false;
291         }
292         memInfo.dataCounts--;
293         return true;
294     }
295 
296 private:
297     template <typename T>
WriteInteger(T & integer,SharedMemoryInfo & memInfo)298     static bool WriteInteger(T &integer, SharedMemoryInfo &memInfo)
299     {
300         uint8_t *src = reinterpret_cast<uint8_t *>(&integer);
301         uint8_t *dest = memInfo.dataPtr;
302         if (memcpy_s(dest, sizeof(T), src, sizeof(T)) != ERR_OK) {
303             HILOG_ERROR("WriteInteger failed:%{public}s", std::strerror(errno));
304             return false;
305         }
306         memInfo.dataPtr += sizeof(T);
307         memInfo.dataSize += sizeof(T);
308         return true;
309     }
310 
311     template <typename T>
ReadInteger(T & integer,SharedMemoryInfo & memInfo)312     static bool ReadInteger(T &integer, SharedMemoryInfo &memInfo)
313     {
314         uint8_t *src = memInfo.dataPtr;
315         uint8_t *dest = reinterpret_cast<uint8_t *>(&integer);
316         if (memcpy_s(dest, sizeof(T), src, sizeof(T)) != ERR_OK) {
317             HILOG_ERROR("ReadInteger 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 
WriteInt32(int32_t & value,SharedMemoryInfo & memInfo)325     static bool WriteInt32(int32_t &value, SharedMemoryInfo &memInfo)
326     {
327         return WriteInteger<int32_t>(value, memInfo);
328     }
329 
WriteInt64(int64_t & value,SharedMemoryInfo & memInfo)330     static bool WriteInt64(int64_t &value, SharedMemoryInfo &memInfo)
331     {
332         return WriteInteger<int64_t>(value, memInfo);
333     }
334 
ReadInt32(int32_t & value,SharedMemoryInfo & memInfo)335     static bool ReadInt32(int32_t &value, SharedMemoryInfo &memInfo)
336     {
337         return ReadInteger<int32_t>(value, memInfo);
338     }
339 
ReadInt64(int64_t & value,SharedMemoryInfo & memInfo)340     static bool ReadInt64(int64_t &value, SharedMemoryInfo &memInfo)
341     {
342         return ReadInteger<int64_t>(value, memInfo);
343     }
344 
WriteString(std::string & inVal,SharedMemoryInfo & memInfo)345     static bool WriteString(std::string &inVal, SharedMemoryInfo &memInfo)
346     {
347         std::string::size_type len = inVal.size();
348         bool ret = WriteInteger<std::string::size_type>(len, memInfo);
349         if (!ret) {
350             return false;
351         }
352         if (len == 0) {
353             return true;
354         }
355 
356         const uint8_t *src = reinterpret_cast<const uint8_t *>(inVal.c_str());
357         uint8_t *dest = memInfo.dataPtr;
358         if (memcpy_s(dest, len, src, len) != ERR_OK) {
359             HILOG_ERROR("WriteString failed:%{public}s", std::strerror(errno));
360             return false;
361         }
362         memInfo.dataPtr += len;
363         memInfo.dataSize += len;
364         return true;
365     }
366 
ReadString(std::string & outVal,SharedMemoryInfo & memInfo)367     static bool ReadString(std::string &outVal, SharedMemoryInfo &memInfo)
368     {
369         std::string::size_type len = 0;
370         int ret = ReadInteger<std::string::size_type>(len, memInfo);
371         if (!ret) {
372             return false;
373         }
374         if (len == 0) {
375             outVal = "";
376             return true;
377         }
378 
379         uint8_t *src = memInfo.dataPtr;
380         uint8_t dest[len + 1];
381         if (memcpy_s(dest, len, src, len) != ERR_OK) {
382             HILOG_ERROR("ReadString failed:%{public}s", std::strerror(errno));
383             return false;
384         }
385         dest[len] = 0;
386         outVal = reinterpret_cast<char *>(dest);
387         memInfo.dataPtr += len;
388         memInfo.dataSize -= len;
389         return true;
390     }
391 
GetFileInfoSize(FileInfo & info)392     static uint64_t GetFileInfoSize(FileInfo &info)
393     {
394         return sizeof(std::string::size_type) + info.uri.size() + sizeof(std::string::size_type) +
395             info.relativePath.size() + sizeof(std::string::size_type) + info.fileName.size() + sizeof(info.mode) +
396             sizeof(info.size) + sizeof(info.mtime) + sizeof(std::string::size_type) + info.mimeType.size();
397     }
398 };
399 } // namespace FileAccessFwk
400 } // namespace OHOS
401 #endif // _FILE_INFO_SHARED_MEMORY_H_
402