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
BooleanArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)112 static bool BooleanArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
113 {
114 bool blValue = false;
115 bool isBool = ParseBool(env, blValue, argv);
116 if (!isBool) {
117 return false;
118 }
119 data.WriteBool(blValue);
120 return true;
121 }
122
Int32ArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)123 static bool Int32ArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
124 {
125 int32_t int32Value = 0;
126 bool isUint = ParseInt(env, int32Value, argv);
127 if (!isUint) {
128 return false;
129 }
130 data.WriteInt32(int32Value);
131 return true;
132 }
133
Int64ArgToData(napi_env env,napi_value argv,MessageParcel & data,const AddonMethodSign & methodSign)134 static bool Int64ArgToData(napi_env env, napi_value argv, MessageParcel &data, const AddonMethodSign &methodSign)
135 {
136 int64_t int64Value = 0;
137 bool isUint = ParseLong(env, int64Value, argv);
138 if (!isUint) {
139 return false;
140 }
141 data.WriteInt64(int64Value);
142 return true;
143 }
144
UserIdArgToData(napi_env env,napi_value * argv,const AddonMethodSign & methodSign,MessageParcel & data,std::string & errorStr)145 static bool UserIdArgToData(napi_env env, napi_value *argv, const AddonMethodSign &methodSign,
146 MessageParcel &data, std::string &errorStr)
147 {
148 auto it = std::find(methodSign.argsType.begin(), methodSign.argsType.end(), EdmAddonCommonType::USERID);
149 if (it != methodSign.argsType.end()) {
150 int32_t index = it - methodSign.argsType.begin();
151 JsArgToData argConvert = methodSign.argsConvert[index];
152 std::ostringstream errorMsg;
153 errorMsg << "The " << index << "th parameter must be number.";
154 if (argConvert == nullptr) {
155 uint32_t userIdValue = 0;
156 bool isUint = ParseUint(env, userIdValue, argv[index]);
157 if (!isUint) {
158 errorStr = errorMsg.str();
159 return false;
160 }
161 data.WriteUint32(HAS_USERID);
162 data.WriteUint32(userIdValue);
163 } else {
164 bool convertResult = argConvert(env, argv[index], data, methodSign);
165 if (!convertResult) {
166 errorStr = errorMsg.str();
167 return false;
168 }
169 }
170 } else {
171 if (methodSign.methodAttribute != MethodAttribute::OPERATE_ADMIN) {
172 data.WriteUint32(WITHOUT_USERID);
173 }
174 }
175 return true;
176 }
177
EdmAddonCommonType2String(EdmAddonCommonType argType)178 static std::string EdmAddonCommonType2String(EdmAddonCommonType argType)
179 {
180 switch (argType) {
181 case EdmAddonCommonType::ELEMENT_NULL:
182 return "want or null";
183 case EdmAddonCommonType::ELEMENT:
184 return "want";
185 case EdmAddonCommonType::UINT32:
186 return "number";
187 case EdmAddonCommonType::STRING:
188 return "string";
189 case EdmAddonCommonType::ARRAY_STRING:
190 return "string array";
191 case EdmAddonCommonType::BOOLEAN:
192 return "bool";
193 case EdmAddonCommonType::INT32:
194 return "number";
195 case EdmAddonCommonType::CUSTOM:
196 /* use custom convert */
197 [[fallthrough]];
198 default:
199 return "object";
200 }
201 }
202
JsParamsToData(napi_env env,napi_value * argv,size_t argc,const AddonMethodSign & methodSign,MessageParcel & data)203 static napi_value JsParamsToData(napi_env env, napi_value *argv, size_t argc,
204 const AddonMethodSign &methodSign, MessageParcel &data)
205 {
206 std::map<EdmAddonCommonType, JsArgToData> funcMap = {
207 {EdmAddonCommonType::ELEMENT_NULL, ElementNullArgToData},
208 {EdmAddonCommonType::ELEMENT, ElementArgToData},
209 {EdmAddonCommonType::UINT32, Uint32ArgToData},
210 {EdmAddonCommonType::STRING, StringArgToData},
211 {EdmAddonCommonType::ARRAY_STRING, ArrayStringArgToData},
212 {EdmAddonCommonType::BOOLEAN, BooleanArgToData},
213 {EdmAddonCommonType::INT32, Int32ArgToData},
214 {EdmAddonCommonType::INT64, Int64ArgToData}
215 };
216
217 for (size_t i = 0; i < methodSign.argsType.size(); i++) {
218 // The value cannot exceed the actual length. Default parameters may exist.
219 if (i >= argc) {
220 break;
221 }
222 EdmAddonCommonType argType = methodSign.argsType[i];
223 JsArgToData argConvert = nullptr;
224 if (methodSign.argsConvert.size() > 0) {
225 argConvert = methodSign.argsConvert[i];
226 }
227 std::ostringstream errorMsg;
228 errorMsg << "The " << i << "th parameter must be ";
229 errorMsg << EdmAddonCommonType2String(argType) << ".";
230 if (argConvert == nullptr) {
231 auto it = funcMap.find(argType);
232 if (it == funcMap.end()) {
233 continue;
234 }
235 bool res = it->second(env, argv[i], data, methodSign);
236 if (!res) {
237 return CreateError(env, EdmReturnErrCode::PARAM_ERROR, errorMsg.str());
238 }
239 } else {
240 bool result = argConvert(env, argv[i], data, methodSign);
241 if (!result) {
242 return CreateError(env, EdmReturnErrCode::PARAM_ERROR, errorMsg.str());
243 }
244 }
245 }
246 return nullptr;
247 }
248
JsObjectToData(napi_env env,napi_callback_info info,const AddonMethodSign & methodSign,AdapterAddonData * addonData)249 napi_value JsObjectToData(napi_env env, napi_callback_info info, const AddonMethodSign &methodSign,
250 AdapterAddonData *addonData)
251 {
252 napi_status status;
253 size_t argc = ARGS_SIZE_FIVE;
254 napi_value argv[ARGS_SIZE_FIVE];
255 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
256 // The size can meet the minimum length
257 size_t minSize = methodSign.argsType.size() - methodSign.defaultArgSize;
258 ASSERT_AND_THROW_PARAM_ERROR(env, argc >= minSize, "parameter count error");
259 EDMLOGI("AddonMethodAdapter JsObjectToData argc:%{public}zu.", argc);
260 if (argc > methodSign.argsType.size()) {
261 bool isCallBack = MatchValueType(env, argv[methodSign.argsType.size()], napi_function);
262 std::ostringstream errorMsg;
263 /* If a callback exists, there must be no default parameter.
264 overloading of callback and default parameter types cannot be supported. */
265 errorMsg << "The " << methodSign.argsType.size() << "th parameter must be callback";
266 ASSERT_AND_THROW_PARAM_ERROR(env, isCallBack, errorMsg.str());
267 }
268 if (!methodSign.argsType.empty() && !methodSign.argsConvert.empty() &&
269 methodSign.argsType.size() != methodSign.argsConvert.size()) {
270 napi_throw(env, CreateError(env, EdmReturnErrCode::PARAM_ERROR));
271 return nullptr;
272 }
273 addonData->data.WriteInterfaceToken(DESCRIPTOR);
274
275 std::string errorStr;
276 bool convertUserIdRes = UserIdArgToData(env, argv, methodSign, addonData->data, errorStr);
277 if (!convertUserIdRes) {
278 napi_throw(env, CreateError(env, EdmReturnErrCode::PARAM_ERROR, errorStr));
279 return nullptr;
280 }
281
282 napi_value errorRes = JsParamsToData(env, argv, argc, methodSign, addonData->data);
283 if (errorRes != nullptr) {
284 napi_throw(env, errorRes);
285 return nullptr;
286 }
287
288 if (argc > methodSign.argsType.size()) {
289 // Assign a value to callback
290 status = napi_create_reference(env, argv[methodSign.argsType.size()], NAPI_RETURN_ONE, &addonData->callback);
291 std::ostringstream errorMsg;
292 errorMsg << "The " << methodSign.argsType.size() << "th parameter must be callback.";
293 ASSERT_AND_THROW_PARAM_ERROR(env, status == napi_ok, errorMsg.str());
294 }
295 napi_value result = nullptr;
296 napi_get_undefined(env, &result);
297 EDMLOGI("AddonMethodAdapter %{public}s JsObjectToData exec success.", methodSign.name.c_str());
298 addonData->policyCode = methodSign.policyCode;
299 return result;
300 }
301
AddonMethodAdapter(napi_env env,napi_callback_info info,const AddonMethodSign & methodSign,napi_async_execute_callback execute,napi_async_complete_callback complete)302 napi_value AddonMethodAdapter(napi_env env, napi_callback_info info, const AddonMethodSign &methodSign,
303 napi_async_execute_callback execute, napi_async_complete_callback complete)
304 {
305 auto adapterAddonData = new (std::nothrow) AdapterAddonData();
306 if (adapterAddonData == nullptr) {
307 return nullptr;
308 }
309 std::unique_ptr<AdapterAddonData> adapterAddonDataPtr {adapterAddonData};
310 napi_value result = JsObjectToData(env, info, methodSign, adapterAddonData);
311 if (result == nullptr) {
312 EDMLOGE("AddonMethodAdapter JsObjectToData exec fail.");
313 return nullptr;
314 }
315 napi_value asyncWorkReturn = HandleAsyncWork(env, adapterAddonData, methodSign.name,
316 execute, complete);
317 adapterAddonDataPtr.release();
318 return asyncWorkReturn;
319 }
320 } // namespace EDM
321 } // namespace OHOS