1 /*
2 * Copyright (c) 2024 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 "napi_edm_adapter.h"
17
18 #include <sstream>
19
20 #include "edm_log.h"
21 #include "napi_edm_common.h"
22 #include "napi_edm_error.h"
23
24 namespace OHOS {
25 namespace EDM {
26 namespace {
27 constexpr int32_t HAS_ADMIN = 0;
28 constexpr int32_t WITHOUT_ADMIN = 1;
29 constexpr int32_t WITHOUT_USERID = 0;
30 constexpr int32_t HAS_USERID = 1;
31 const std::u16string DESCRIPTOR = u"ohos.edm.IEnterpriseDeviceMgr";
32 }
33
ElementNullArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)34 static bool ElementNullArgToData(napi_env env, napi_value argv, MessageParcel &data,
35 const AddonMethodSign &methodSign)
36 {
37 if (methodSign.methodAttribute == MethodAttribute::GET) {
38 data.WriteString(methodSign.apiVersionTag);
39 }
40 OHOS::AppExecFwk::ElementName elementName;
41 bool isElement = ParseElementName(env, elementName, argv);
42 bool isNull = MatchValueType(env, argv, napi_null);
43 if (!isElement && !isNull) {
44 return false;
45 }
46 if (isNull) {
47 data.WriteInt32(WITHOUT_ADMIN);
48 } else {
49 data.WriteInt32(HAS_ADMIN);
50 data.WriteParcelable(&elementName);
51 }
52 if (methodSign.methodAttribute == MethodAttribute::HANDLE) {
53 data.WriteString(methodSign.apiVersionTag);
54 }
55 return true;
56 }
57
ElementArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)58 static bool ElementArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
59 {
60 if (methodSign.methodAttribute == MethodAttribute::GET) {
61 data.WriteString(methodSign.apiVersionTag);
62 }
63 OHOS::AppExecFwk::ElementName elementName;
64 bool isElement = ParseElementName(env, elementName, argv);
65 if (!isElement) {
66 return false;
67 }
68 if (methodSign.methodAttribute == MethodAttribute::GET) {
69 data.WriteInt32(HAS_ADMIN);
70 }
71 data.WriteParcelable(&elementName);
72 if (methodSign.methodAttribute == MethodAttribute::HANDLE) {
73 data.WriteString(methodSign.apiVersionTag);
74 }
75 return true;
76 }
77
Uint32ArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)78 static bool Uint32ArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
79 {
80 uint32_t uintValue = 0;
81 bool isUint = ParseUint(env, uintValue, argv);
82 if (!isUint) {
83 return false;
84 }
85 data.WriteUint32(uintValue);
86 return true;
87 }
88
StringArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)89 static bool StringArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
90 {
91 std::string strValue;
92 bool isString = ParseString(env, strValue, argv);
93 if (!isString) {
94 return false;
95 }
96 data.WriteString(strValue);
97 return true;
98 }
99
ArrayStringArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)100 static bool ArrayStringArgToData(napi_env env, napi_value argv, MessageParcel &data,
101 const AddonMethodSign &methodSign)
102 {
103 std::vector<std::string> strArrValue;
104 bool isStringArr = ParseStringArray(env, strArrValue, argv);
105 if (!isStringArr) {
106 return false;
107 }
108 data.WriteStringVector(strArrValue);
109 return true;
110 }
111
ArrayIntArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)112 static bool ArrayIntArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
113 {
114 std::vector<int32_t> intArrValue;
115 bool isIntArr = ParseIntArray(env, intArrValue, argv);
116 if (!isIntArr) {
117 return false;
118 }
119 data.WriteInt32Vector(intArrValue);
120 return true;
121 }
122
BooleanArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)123 static bool BooleanArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
124 {
125 bool blValue = false;
126 bool isBool = ParseBool(env, blValue, argv);
127 if (!isBool) {
128 return false;
129 }
130 data.WriteBool(blValue);
131 return true;
132 }
133
Int32ArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)134 static bool Int32ArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
135 {
136 int32_t int32Value = 0;
137 bool isUint = ParseInt(env, int32Value, argv);
138 if (!isUint) {
139 return false;
140 }
141 data.WriteInt32(int32Value);
142 return true;
143 }
144
Int64ArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)145 static bool Int64ArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
146 {
147 int64_t int64Value = 0;
148 bool isUint = ParseLong(env, int64Value, argv);
149 if (!isUint) {
150 return false;
151 }
152 data.WriteInt64(int64Value);
153 return true;
154 }
155
UserIdArgToData(napi_env env,napi_value * argv,const AddonMethodSign & methodSign,MessageParcel & data,std::string & errorStr)156 static bool UserIdArgToData(napi_env env, napi_value *argv, const AddonMethodSign &methodSign,
157 MessageParcel &data, std::string &errorStr)
158 {
159 auto it = std::find(methodSign.argsType.begin(), methodSign.argsType.end(), EdmAddonCommonType::USERID);
160 if (it != methodSign.argsType.end()) {
161 int32_t index = it - methodSign.argsType.begin();
162 JsArgToData argConvert = methodSign.argsConvert[index];
163 std::ostringstream errorMsg;
164 errorMsg << "The " << index << "th parameter must be number.";
165 if (argConvert == nullptr) {
166 uint32_t userIdValue = 0;
167 bool isUint = ParseUint(env, userIdValue, argv[index]);
168 if (!isUint) {
169 errorStr = errorMsg.str();
170 return false;
171 }
172 data.WriteUint32(HAS_USERID);
173 data.WriteUint32(userIdValue);
174 } else {
175 bool convertResult = argConvert(env, argv[index], data, methodSign);
176 if (!convertResult) {
177 errorStr = errorMsg.str();
178 return false;
179 }
180 }
181 } else {
182 if (methodSign.methodAttribute != MethodAttribute::OPERATE_ADMIN) {
183 data.WriteUint32(WITHOUT_USERID);
184 }
185 }
186 return true;
187 }
188
EdmAddonCommonType2String(EdmAddonCommonType argType)189 static std::string EdmAddonCommonType2String(EdmAddonCommonType argType)
190 {
191 switch (argType) {
192 case EdmAddonCommonType::ELEMENT_NULL:
193 return "want or null";
194 case EdmAddonCommonType::ELEMENT:
195 return "want";
196 case EdmAddonCommonType::UINT32:
197 return "number";
198 case EdmAddonCommonType::STRING:
199 return "string";
200 case EdmAddonCommonType::ARRAY_STRING:
201 return "string array";
202 case EdmAddonCommonType::BOOLEAN:
203 return "bool";
204 case EdmAddonCommonType::INT32:
205 return "number";
206 case EdmAddonCommonType::ARRAY_INT32:
207 return "number array";
208 case EdmAddonCommonType::CUSTOM:
209 /* use custom convert */
210 [[fallthrough]];
211 default:
212 return "object";
213 }
214 }
215
JsParamsToData(napi_env env,napi_value * argv,size_t argc,const AddonMethodSign & methodSign,MessageParcel & data)216 static napi_value JsParamsToData(napi_env env, napi_value *argv, size_t argc,
217 const AddonMethodSign &methodSign, MessageParcel &data)
218 {
219 std::map<EdmAddonCommonType, JsArgToData> funcMap = {
220 {EdmAddonCommonType::ELEMENT_NULL, ElementNullArgToData},
221 {EdmAddonCommonType::ELEMENT, ElementArgToData},
222 {EdmAddonCommonType::UINT32, Uint32ArgToData},
223 {EdmAddonCommonType::STRING, StringArgToData},
224 {EdmAddonCommonType::ARRAY_STRING, ArrayStringArgToData},
225 {EdmAddonCommonType::BOOLEAN, BooleanArgToData},
226 {EdmAddonCommonType::INT32, Int32ArgToData},
227 {EdmAddonCommonType::INT64, Int64ArgToData},
228 {EdmAddonCommonType::ARRAY_INT32, ArrayIntArgToData},
229 };
230
231 for (size_t i = 0; i < methodSign.argsType.size(); i++) {
232 // The value cannot exceed the actual length. Default parameters may exist.
233 if (i >= argc) {
234 break;
235 }
236 EdmAddonCommonType argType = methodSign.argsType[i];
237 JsArgToData argConvert = nullptr;
238 if (methodSign.argsConvert.size() > 0) {
239 argConvert = methodSign.argsConvert[i];
240 }
241 std::ostringstream errorMsg;
242 errorMsg << "The " << i << "th parameter must be ";
243 errorMsg << EdmAddonCommonType2String(argType) << ".";
244 if (argConvert == nullptr) {
245 auto it = funcMap.find(argType);
246 if (it == funcMap.end()) {
247 continue;
248 }
249 bool res = it->second(env, argv[i], data, methodSign);
250 if (!res) {
251 return CreateError(env, EdmReturnErrCode::PARAM_ERROR, errorMsg.str());
252 }
253 } else {
254 bool result = argConvert(env, argv[i], data, methodSign);
255 if (!result) {
256 return CreateError(env, EdmReturnErrCode::PARAM_ERROR, errorMsg.str());
257 }
258 }
259 }
260 return nullptr;
261 }
262
JsObjectToData(napi_env env,napi_callback_info info,const AddonMethodSign & methodSign,AdapterAddonData * addonData,bool isAsync)263 napi_value JsObjectToData(napi_env env, napi_callback_info info, const AddonMethodSign &methodSign,
264 AdapterAddonData *addonData, bool isAsync)
265 {
266 napi_status status;
267 size_t argc = ARGS_SIZE_FIVE;
268 napi_value argv[ARGS_SIZE_FIVE];
269 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
270 // The size can meet the minimum length
271 size_t minSize = methodSign.argsType.size() - methodSign.defaultArgSize;
272 ASSERT_AND_THROW_PARAM_ERROR(env, argc >= minSize, "parameter count error");
273 EDMLOGI("AddonMethodAdapter JsObjectToData argc:%{public}zu.", argc);
274 if (isAsync && argc > methodSign.argsType.size()) {
275 bool isCallBack = MatchValueType(env, argv[methodSign.argsType.size()], napi_function);
276 std::ostringstream errorMsg;
277 /* If a callback exists, there must be no default parameter.
278 overloading of callback and default parameter types cannot be supported. */
279 errorMsg << "The " << methodSign.argsType.size() << "th parameter must be callback";
280 ASSERT_AND_THROW_PARAM_ERROR(env, isCallBack, errorMsg.str());
281 }
282 if (!methodSign.argsType.empty() && !methodSign.argsConvert.empty() &&
283 methodSign.argsType.size() != methodSign.argsConvert.size()) {
284 napi_throw(env, CreateError(env, EdmReturnErrCode::PARAM_ERROR));
285 return nullptr;
286 }
287 addonData->data.WriteInterfaceToken(DESCRIPTOR);
288
289 std::string errorStr;
290 bool convertUserIdRes = UserIdArgToData(env, argv, methodSign, addonData->data, errorStr);
291 if (!convertUserIdRes) {
292 napi_throw(env, CreateError(env, EdmReturnErrCode::PARAM_ERROR, errorStr));
293 return nullptr;
294 }
295
296 napi_value errorRes = JsParamsToData(env, argv, argc, methodSign, addonData->data);
297 if (errorRes != nullptr) {
298 napi_throw(env, errorRes);
299 return nullptr;
300 }
301
302 if (argc > methodSign.argsType.size()) {
303 // Assign a value to callback
304 status = napi_create_reference(env, argv[methodSign.argsType.size()], NAPI_RETURN_ONE, &addonData->callback);
305 std::ostringstream errorMsg;
306 errorMsg << "The " << methodSign.argsType.size() << "th parameter must be callback.";
307 ASSERT_AND_THROW_PARAM_ERROR(env, status == napi_ok, errorMsg.str());
308 }
309 napi_value result = nullptr;
310 napi_get_undefined(env, &result);
311 EDMLOGI("AddonMethodAdapter %{public}s JsObjectToData exec success.", methodSign.name.c_str());
312 addonData->policyCode = methodSign.policyCode;
313 return result;
314 }
315
AddonMethodAdapter(napi_env env,napi_callback_info info,const AddonMethodSign & methodSign,napi_async_execute_callback execute,napi_async_complete_callback complete)316 napi_value AddonMethodAdapter(napi_env env, napi_callback_info info, const AddonMethodSign &methodSign,
317 napi_async_execute_callback execute, napi_async_complete_callback complete)
318 {
319 auto adapterAddonData = new (std::nothrow) AdapterAddonData();
320 if (adapterAddonData == nullptr) {
321 return nullptr;
322 }
323 std::unique_ptr<AdapterAddonData> adapterAddonDataPtr {adapterAddonData};
324 napi_value result = JsObjectToData(env, info, methodSign, adapterAddonData, true);
325 if (result == nullptr) {
326 EDMLOGE("AddonMethodAdapter JsObjectToData exec fail.");
327 return nullptr;
328 }
329 napi_value asyncWorkReturn = HandleAsyncWork(env, adapterAddonData, methodSign.name,
330 execute, complete);
331 adapterAddonDataPtr.release();
332 return asyncWorkReturn;
333 }
334 } // namespace EDM
335 } // namespace OHOS