• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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