• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "platform/os_wrapper/ipc/include/aie_ipc.h"
17 
18 #include <cstdlib>
19 #include <sys/shm.h>
20 
21 #include "securec.h"
22 
23 #include "protocol/retcode_inner/aie_retcode_inner.h"
24 #include "utils/aie_guard.h"
25 #include "utils/log/aie_log.h"
26 
27 namespace {
28 constexpr int IPC_MAX_TRANS_CAPACITY = 200; // memory beyond this limit will use shared memory
29 constexpr int SHM_KEY_START = 200000; // chosen randomly
30 constexpr int SHM_KEY_END   = 300000; // chosen randomly
31 constexpr unsigned int SHM_READ_WRITE_PERMISSIONS = 0777U;
32 
ReleaseShmId(const int shmId)33 void ReleaseShmId(const int shmId)
34 {
35     if (shmId == -1) {
36         return;
37     }
38     if (shmctl(shmId, IPC_RMID, nullptr) == -1) {
39         HILOGE("[AieIpc]shmctl IPC_RMID failed: %d.", errno);
40         return;
41     }
42 }
43 
44 /**
45  * Use shared memory to push large memory.
46  *
47  * @param [in] request Ipc handle.
48  * @param [in] dataInfo Data need to transfer.
49  * @param receiverUid receiver's uid.
50  */
IpcIoPushSharedMemory(IpcIo * request,const DataInfo * dataInfo,const uid_t receiverUid)51 void IpcIoPushSharedMemory(IpcIo *request, const DataInfo *dataInfo, const uid_t receiverUid)
52 {
53     // internal call, no need to check null.
54     static int shmKey = SHM_KEY_START;
55     int shmId;
56     while ((shmId = shmget(shmKey, dataInfo->length, SHM_READ_WRITE_PERMISSIONS | IPC_CREAT | IPC_EXCL)) < 0) {
57         if (errno == EEXIST) {
58             ++shmKey;
59             if (shmKey >= SHM_KEY_END) {
60                 shmKey = SHM_KEY_START;
61             }
62             continue;
63         }
64         HILOGE("[AieIpc]shmget failed: %d.", errno);
65         return;
66     }
67     HILOGI("[AieIpc]shmget succeed, shmKey = %d, shmId = %d.", shmKey, shmId);
68 
69     char *shared = reinterpret_cast<char *>(shmat(shmId, nullptr, 0));
70     if (shared == reinterpret_cast<char *>(-1)) {
71         ReleaseShmId(shmId);
72         HILOGE("[AieIpc]shmat failed: %d.", errno);
73         return;
74     }
75 
76     int retCode;
77     if ((retCode = memcpy_s(shared, dataInfo->length, dataInfo->data, dataInfo->length)) != EOK) {
78         shmdt(shared);
79         ReleaseShmId(shmId);
80         HILOGE("[AieIpc]memcpy_s failed: %d.", retCode);
81         return;
82     }
83 
84     if (shmdt(shared) == -1) {
85         ReleaseShmId(shmId);
86         HILOGE("[AieIpc]shmdt failed: %d.", errno);
87         return;
88     }
89 
90     struct shmid_ds shmidDs {};
91     if (shmctl(shmId, IPC_STAT, &shmidDs) == -1) {
92         HILOGE("[AieIpc]shmctl IPC_STAT failed: %d.", errno);
93         ReleaseShmId(shmId);
94     }
95 
96     shmidDs.shm_perm.uid = receiverUid; // give receiver the privilege to release shared memory.
97     if (shmctl(shmId, IPC_SET, &shmidDs) == -1) {
98         ReleaseShmId(shmId);
99         HILOGE("[AieIpc]shmctl IPC_SET failed: %d.", errno);
100         return;
101     }
102 
103     IpcIoPushInt32(request, shmId);
104     IpcIoPushInt32(request, dataInfo->length);
105 }
106 
107 /**
108  * Use shared memory to pop large memory.
109  *
110  * @param [in] request Ipc handle.
111  * @param [out] dataInfo Data received.
112  * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.
113  */
IpcIoPopSharedMemory(IpcIo * request,DataInfo * dataInfo)114 int IpcIoPopSharedMemory(IpcIo *request, DataInfo *dataInfo)
115 {
116     // internal call, no need to check null.
117     int shmId = IpcIoPopInt32(request);
118     dataInfo->length = IpcIoPopInt32(request); // make sure all data are popped out.
119 
120     if (shmId == -1) {
121         HILOGE("[AieIpc]shmId is invalid: %d.", shmId);
122         return RETCODE_FAILURE;
123     }
124     if (dataInfo->length <= 0) {
125         HILOGE("[AieIpc]dataInfo->length is invalid: %d.", dataInfo->length);
126         ReleaseShmId(shmId);
127         return RETCODE_FAILURE;
128     }
129 
130     char *shared = reinterpret_cast<char *>(shmat(shmId, nullptr, 0));
131     if (shared == reinterpret_cast<char *>(-1)) {
132         HILOGE("[AieIpc]shmat failed %d.", errno);
133         ReleaseShmId(shmId);
134         return RETCODE_FAILURE;
135     }
136 
137     if (shared == nullptr) {
138         HILOGE("[AieIpc]shared data is nullptr.");
139         ReleaseShmId(shmId);
140         return RETCODE_NULL_PARAM;
141     }
142 
143     dataInfo->data = reinterpret_cast<unsigned char *>(malloc(dataInfo->length));
144     if (dataInfo->data == nullptr) {
145         shmdt(shared);
146         ReleaseShmId(shmId);
147         HILOGE("[AieIpc]Failed to malloc memory.");
148         return RETCODE_OUT_OF_MEMORY;
149     }
150     OHOS::AI::MallocPointerGuard<unsigned char> dataInfoGuard(dataInfo->data);
151 
152     errno_t retCode = memcpy_s(dataInfo->data, dataInfo->length, shared, dataInfo->length);
153     if (retCode != EOK) {
154         shmdt(shared);
155         ReleaseShmId(shmId);
156         HILOGE("[AieIpc]Failed to memory copy, retCode[%d].", retCode);
157         return RETCODE_MEMORY_COPY_FAILURE;
158     }
159 
160     if (shmdt(shared) == -1) {
161         ReleaseShmId(shmId);
162         HILOGE("[AieIpc]shmdt failed: %d.", errno);
163         return RETCODE_FAILURE;
164     }
165 
166     ReleaseShmId(shmId);
167 
168     dataInfoGuard.Detach();
169     return RETCODE_SUCCESS;
170 }
171 
172 /**
173  * Use ipc to pop memory.
174  *
175  * @param [in] request Ipc handle.
176  * @param [out] dataInfo Data received.
177  * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.
178  */
IpcIoPopMemory(IpcIo * request,DataInfo * dataInfo)179 int IpcIoPopMemory(IpcIo *request, DataInfo *dataInfo)
180 {
181     // internal call, no need to check null.
182     uint32_t dataBufSize = 0;
183     void *dataBuf = IpcIoPopFlatObj(request, &dataBufSize);
184     if (dataBuf == nullptr) {
185         HILOGE("[AieIpc]The UnParcel dataBuf is invalid.");
186         return RETCODE_NULL_PARAM;
187     }
188     if (static_cast<int>(dataBufSize) != dataInfo->length) {
189         HILOGE("[AieIpc]The UnParcel dataBufSize[%ud] doesn't match dataInfo->length[%d].",
190             dataBufSize, dataInfo->length);
191         return RETCODE_NULL_PARAM;
192     }
193 
194     dataInfo->data = reinterpret_cast<unsigned char *>(malloc(dataBufSize));
195     if (dataInfo->data == nullptr) {
196         HILOGE("[AieIpc]Failed to malloc memory.");
197         return RETCODE_OUT_OF_MEMORY;
198     }
199     errno_t retCode = memcpy_s(dataInfo->data, dataInfo->length, dataBuf, dataBufSize);
200     if (retCode != EOK) {
201         HILOGE("[AieIpc]Failed to memory copy, retCode[%d].", retCode);
202         FreeDataInfo(dataInfo);
203         return RETCODE_MEMORY_COPY_FAILURE;
204     }
205     return RETCODE_SUCCESS;
206 }
207 } // anonymous namespace
208 
ParcelDataInfo(IpcIo * request,const DataInfo * dataInfo,const uid_t receiverUid)209 void ParcelDataInfo(IpcIo *request, const DataInfo *dataInfo, const uid_t receiverUid)
210 {
211     if (dataInfo == nullptr) {
212         HILOGE("[AieIpc]The dataInfo is invalid.");
213         return;
214     }
215     if (request == nullptr) {
216         HILOGE("[AieIpc]The request is nullptr.");
217         return;
218     }
219     if (dataInfo->data != nullptr && dataInfo->length <= 0) { // invalid datainfo
220         HILOGE("[AieIpc]dataInfo->data != nullptr, dataInfo->length <= 0.");
221         return;
222     }
223     if (dataInfo->data == nullptr && dataInfo->length != 0) {  // invalid datainfo
224         HILOGE("[AieIpc]dataInfo->data == nullptr, dataInfo->length != 0.");
225         return;
226     }
227 
228     // parcel data length first.
229     IpcIoPushInt32(request, dataInfo->length);
230     if (dataInfo->data == nullptr && dataInfo->length == 0) { // empty datainfo, no need to parcel, save length(0) only.
231         return;
232     }
233     // parcel the data only if the data length > 0
234     if (dataInfo->length < IPC_MAX_TRANS_CAPACITY) {
235         IpcIoPushFlatObj(request, dataInfo->data, static_cast<uint32_t>(dataInfo->length));
236     } else {
237         IpcIoPushSharedMemory(request, dataInfo, receiverUid);
238     }
239 }
240 
UnParcelDataInfo(IpcIo * request,DataInfo * dataInfo)241 int UnParcelDataInfo(IpcIo *request, DataInfo *dataInfo)
242 {
243     if (request == nullptr) {
244         HILOGE("[AieIpc]The request is nullptr.");
245         return RETCODE_FAILURE;
246     }
247     if (dataInfo == nullptr) {
248         HILOGE("[AieIpc]The dataInfo is nullptr.");
249         return RETCODE_FAILURE;
250     }
251 
252     dataInfo->length = IpcIoPopInt32(request);
253     if (dataInfo->length < 0) {
254         HILOGE("[AieIpc]The dataInfo length is invalid.");
255         return RETCODE_FAILURE;
256     }
257     if (dataInfo->length == 0) { // no following buffer to unparcel.
258         dataInfo->data = nullptr;
259         return RETCODE_SUCCESS;
260     }
261 
262     if (dataInfo->length < IPC_MAX_TRANS_CAPACITY) {
263         return IpcIoPopMemory(request, dataInfo);
264     } else {
265         return IpcIoPopSharedMemory(request, dataInfo);
266     }
267 }
268 
FreeDataInfo(DataInfo * dataInfo)269 void FreeDataInfo(DataInfo *dataInfo)
270 {
271     if (dataInfo != nullptr && dataInfo->data != nullptr) {
272         free(dataInfo->data);
273         dataInfo->data = nullptr;
274         dataInfo->length = 0;
275     }
276 }
277