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 "ipc_dev_auth_stub.h"
17
18 #include "common_defs.h"
19 #include "hc_log.h"
20 #include "ipc_adapt.h"
21 #include "ipc_callback_stub.h"
22 #include "ipc_sdk.h"
23 #include "permission_adapter.h"
24 #include "securec.h"
25 #include "system_ability_definition.h"
26
27 using namespace std;
28 namespace OHOS {
29 static std::mutex g_cBMutex;
30
31 struct CbStubInfo {
32 sptr<IRemoteObject> cbStub;
33 bool inUse;
34 };
35 static struct CbStubInfo g_cbStub[MAX_CBSTUB_SIZE];
36 static bool g_cbStubInited = false;
37
ServiceDevAuth()38 ServiceDevAuth::ServiceDevAuth()
39 {}
40
~ServiceDevAuth()41 ServiceDevAuth::~ServiceDevAuth()
42 {
43 maxCallMapSz = MAX_CALLMAP_SIZE;
44 if (callMapTable != nullptr) {
45 delete[] callMapTable;
46 callMapTable = nullptr;
47 }
48 callMapElemNum = 0;
49 }
50
GetCallMethodByMethodId(int32_t methodId)51 IpcServiceCall ServiceDevAuth::GetCallMethodByMethodId(int32_t methodId)
52 {
53 int32_t i;
54
55 if (callMapTable == nullptr) {
56 return nullptr;
57 }
58
59 for (i = 0; i < maxCallMapSz; i++) {
60 if ((callMapTable[i].methodId == methodId) && (callMapTable[i].method != nullptr)) {
61 return callMapTable[i].method;
62 }
63 }
64 return nullptr;
65 }
66
DecodeCallRequest(MessageParcel & data,IpcDataInfo * paramsCache,int32_t cacheNum,int32_t & inParamNum)67 static int32_t DecodeCallRequest(MessageParcel &data, IpcDataInfo *paramsCache, int32_t cacheNum, int32_t &inParamNum)
68 {
69 int32_t dataLen = 0;
70 int32_t i;
71 int32_t ret;
72
73 if (data.GetReadableBytes() == 0) {
74 return HC_SUCCESS;
75 }
76
77 data.ReadInt32(dataLen);
78 if (dataLen > static_cast<int32_t>(data.GetReadableBytes())) {
79 return HC_ERR_IPC_BAD_MESSAGE_LENGTH;
80 }
81
82 data.ReadInt32(inParamNum);
83 if ((inParamNum < 0) || (inParamNum > cacheNum)) {
84 LOGE("param number invalid, inParamNum - %d", inParamNum);
85 return HC_ERR_IPC_BAD_PARAM_NUM;
86 }
87 LOGI("param number: %d", inParamNum);
88
89 for (i = 0; i < inParamNum; i++) {
90 ret = DecodeIpcData(reinterpret_cast<uintptr_t>(&data), &(paramsCache[i].type),
91 &(paramsCache[i].val), &(paramsCache[i].valSz));
92 if (ret != HC_SUCCESS) {
93 LOGE("decode failed, ret %d", ret);
94 return ret;
95 }
96 LOGI("decode success, param type %d, val size %d", paramsCache[i].type, paramsCache[i].valSz);
97 }
98 return HC_SUCCESS;
99 }
100
GetMethodId(MessageParcel & data,int32_t & methodId)101 static int32_t GetMethodId(MessageParcel &data, int32_t &methodId)
102 {
103 if (data.GetDataSize() < sizeof(int32_t)) {
104 return HC_ERR_IPC_CALL_DATA_LENGTH;
105 }
106 methodId = data.ReadInt32();
107 LOGI("GetMethodId, id code %d", methodId);
108 return HC_SUCCESS;
109 }
110
WithObject(int32_t methodId,MessageParcel & data,IpcDataInfo & ipcData,int32_t & cnt)111 static void WithObject(int32_t methodId, MessageParcel &data, IpcDataInfo &ipcData, int32_t &cnt)
112 {
113 if (IsCallbackMethod(methodId)) {
114 ipcData.type = data.ReadInt32();
115 ipcData.valSz = sizeof(StubDevAuthCb);
116 sptr<IRemoteObject> tmp = data.ReadRemoteObject();
117 if (!tmp) {
118 LOGE("should with remote object, but read failed");
119 return;
120 }
121 ipcData.idx = ServiceDevAuth::SetRemoteObject(tmp);
122 if (ipcData.idx >= 0) {
123 ipcData.val = reinterpret_cast<uint8_t *>(&(ipcData.idx));
124 LOGI("object trans success, set id %d", ipcData.idx);
125 cnt++;
126 }
127 }
128 return;
129 }
130
InitCbStubTable()131 static void InitCbStubTable()
132 {
133 int32_t i;
134 if (g_cbStubInited) {
135 return;
136 }
137 std::lock_guard<std::mutex> autoLock(g_cBMutex);
138 if (g_cbStubInited) { /* for first init at the same time */
139 return;
140 }
141 for (i = 0; i < MAX_CBSTUB_SIZE; i++) {
142 g_cbStub[i].inUse = false;
143 }
144 g_cbStubInited = true;
145 return;
146 }
147
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)148 int32_t ServiceDevAuth::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
149 {
150 if (data.ReadInterfaceToken() != GetDescriptor()) {
151 LOGE("[IPC][C->S]: The proxy interface token is invalid!");
152 return -1;
153 }
154 if (CheckPermission() != HC_SUCCESS) {
155 return -1;
156 }
157 int32_t ret = HC_ERR_IPC_UNKNOW_OPCODE;
158 int32_t dataLen;
159 int32_t methodId = 0;
160 int32_t reqParamNum = 0;
161 MessageParcel replyCache;
162 IpcDataInfo reqParams[MAX_REQUEST_PARAMS_NUM] = {{0}};
163 IpcServiceCall serviceCall = nullptr;
164
165 LOGI("request code %u", code);
166 switch (code) {
167 case DEV_AUTH_CALL_REQUEST:
168 ret = GetMethodId(data, methodId);
169 if (ret != HC_SUCCESS) {
170 break;
171 }
172 serviceCall = GetCallMethodByMethodId(methodId);
173 if (serviceCall == nullptr) {
174 ret = HC_ERR_IPC_METHOD_ID_INVALID;
175 break;
176 }
177 ret = DecodeCallRequest(data, reqParams, MAX_REQUEST_PARAMS_NUM, reqParamNum);
178 if (ret != HC_SUCCESS) {
179 break;
180 }
181 if (reqParamNum < (MAX_REQUEST_PARAMS_NUM - 1)) {
182 InitCbStubTable();
183 WithObject(methodId, data, reqParams[reqParamNum], reqParamNum);
184 }
185 ret = serviceCall(reqParams, reqParamNum, reinterpret_cast<uintptr_t>(&replyCache));
186 break;
187 default:
188 break;
189 }
190 reply.WriteInt32(ret);
191 dataLen = replyCache.GetDataSize();
192 if (dataLen > 0) {
193 reply.WriteInt32(dataLen);
194 reply.WriteBuffer(reinterpret_cast<const void *>(replyCache.GetData()), dataLen);
195 }
196 LOGI("done, request code %u, method id %d, call result %d", code, methodId, ret);
197 return 0;
198 }
199
SetCallMap(IpcServiceCall method,int32_t methodId)200 int32_t ServiceDevAuth::SetCallMap(IpcServiceCall method, int32_t methodId)
201 {
202 int32_t len;
203 errno_t eno;
204 IpcServiceCallMap *callMapTmp = nullptr;
205
206 if ((1 + callMapElemNum) > maxCallMapSz) {
207 maxCallMapSz += MAX_CALLMAP_SIZE;
208 if (callMapTable != nullptr) {
209 callMapTmp = callMapTable;
210 callMapTable = nullptr;
211 }
212 }
213 if (callMapTable == nullptr) {
214 callMapTable = new(std::nothrow) IpcServiceCallMap[maxCallMapSz];
215 if (callMapTable == nullptr) {
216 return HC_ERR_ALLOC_MEMORY;
217 }
218 len = sizeof(IpcServiceCallMap) * maxCallMapSz;
219 (void)memset_s(callMapTable, len, 0, len);
220 if (callMapTmp != nullptr) {
221 eno = memcpy_s(callMapTable, len, callMapTmp, (sizeof(IpcServiceCallMap) * callMapElemNum));
222 if (eno != EOK) {
223 delete[] callMapTable;
224 callMapTable = callMapTmp;
225 maxCallMapSz -= MAX_CALLMAP_SIZE;
226 return HC_ERR_MEMORY_COPY;
227 }
228 delete[] callMapTmp;
229 callMapTmp = nullptr;
230 }
231 }
232 callMapTable[callMapElemNum].method = method;
233 callMapTable[callMapElemNum].methodId = methodId;
234 callMapElemNum++;
235 return HC_SUCCESS;
236 }
237
SetRemoteObject(sptr<IRemoteObject> & object)238 int32_t ServiceDevAuth::SetRemoteObject(sptr<IRemoteObject> &object)
239 {
240 int32_t idx = -1;
241 int32_t i;
242
243 std::lock_guard<std::mutex> autoLock(g_cBMutex);
244 for (i = 0; i < MAX_CBSTUB_SIZE; i++) {
245 if (!g_cbStub[i].inUse) {
246 idx = i;
247 break;
248 }
249 }
250 LOGI("remote object cache index %d", idx);
251 if (idx == -1) {
252 return -1;
253 }
254 g_cbStub[idx].cbStub = object;
255 g_cbStub[idx].inUse = true;
256 return idx;
257 }
258
SetCbDeathRecipient(int32_t objIdx,int32_t cbDataIdx)259 void ServiceDevAuth::SetCbDeathRecipient(int32_t objIdx, int32_t cbDataIdx)
260 {
261 bool bRet = false;
262 if ((objIdx < 0) || (objIdx >= MAX_CBSTUB_SIZE) || (!g_cbStub[objIdx].inUse)) {
263 return;
264 }
265
266 std::lock_guard<std::mutex> autoLock(g_cBMutex);
267 bRet = g_cbStub[objIdx].cbStub->AddDeathRecipient(new(std::nothrow) DevAuthDeathRecipient(cbDataIdx));
268 LOGI("AddDeathRecipient %s, callback stub idx %d", bRet ? "success" : "failed", objIdx);
269 return;
270 }
271
ResetRemoteObject(int32_t idx)272 void ServiceDevAuth::ResetRemoteObject(int32_t idx)
273 {
274 if ((idx >= 0) && (idx < MAX_CBSTUB_SIZE)) {
275 LOGI("remote object used done, idx %d", idx);
276 std::lock_guard<std::mutex> autoLock(g_cBMutex);
277 g_cbStub[idx].inUse = false;
278 }
279 return;
280 }
281
ActCallback(int32_t objIdx,int32_t callbackId,bool sync,uintptr_t cbHook,MessageParcel & dataParcel,MessageParcel & reply)282 void ServiceDevAuth::ActCallback(int32_t objIdx, int32_t callbackId, bool sync,
283 uintptr_t cbHook, MessageParcel &dataParcel, MessageParcel &reply)
284 {
285 if ((objIdx < 0) || (objIdx >= MAX_CBSTUB_SIZE) || (!g_cbStub[objIdx].inUse)) {
286 LOGW("nothing to do, callback id %d, remote object id %d", callbackId, objIdx);
287 return;
288 }
289 MessageOption option(MessageOption::TF_SYNC);
290 option.SetWaitTime(DEV_AUTH_CALL_WAIT_TIME);
291 if (!sync) {
292 option.SetFlags(MessageOption::TF_ASYNC);
293 option.SetWaitTime(0);
294 }
295 std::lock_guard<std::mutex> autoLock(g_cBMutex);
296 sptr<ICommIpcCallback> proxy = iface_cast<ICommIpcCallback>(g_cbStub[objIdx].cbStub);
297 proxy->DoCallBack(callbackId, cbHook, dataParcel, reply, option);
298 return;
299 }
300
DevAuthDeathRecipient(int32_t cbIdx)301 DevAuthDeathRecipient::DevAuthDeathRecipient(int32_t cbIdx)
302 {
303 callbackIdx = cbIdx;
304 }
305
OnRemoteDied(const wptr<IRemoteObject> & remoteObject)306 void DevAuthDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remoteObject)
307 {
308 LOGI("remote is not actively, to reset local resource");
309 ResetIpcCallBackNodeByNodeId(callbackIdx);
310 }
311 }
312