1 /*
2  * Copyright (c) 2022-2023 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 #include "permission_record_manager_napi.h"
16 #include <cinttypes>
17 #include <vector>
18 #include "privacy_kit.h"
19 #include "accesstoken_log.h"
20 #include "napi_context_common.h"
21 #include "napi_common.h"
22 #include "napi_error.h"
23 #include "napi/native_api.h"
24 #include "napi/native_node_api.h"
25 #include "privacy_error.h"
26 
27 namespace OHOS {
28 namespace Security {
29 namespace AccessToken {
30 std::mutex g_lockForPermActiveChangeSubscribers;
31 std::vector<RegisterPermActiveChangeContext*> g_permActiveChangeSubscribers;
32 static constexpr size_t MAX_CALLBACK_SIZE = 200;
33 static constexpr int32_t ADD_PERMISSION_RECORD_MAX_PARAMS = 5;
34 static constexpr int32_t ADD_PERMISSION_RECORD_MIN_PARAMS = 4;
35 static constexpr int32_t GET_PERMISSION_RECORD_MAX_PARAMS = 2;
36 static constexpr int32_t ON_OFF_MAX_PARAMS = 3;
37 static constexpr int32_t START_STOP_MAX_PARAMS = 3;
38 static constexpr int32_t GET_PERMISSION_USED_TYPE_MAX_PARAMS = 2;
39 static constexpr int32_t GET_PERMISSION_USED_TYPE_ONE_PARAMS = 1;
40 static constexpr int32_t FIRST_PARAM = 0;
41 static constexpr int32_t SECOND_PARAM = 1;
42 static constexpr int32_t THIRD_PARAM = 2;
43 static constexpr int32_t FOURTH_PARAM = 3;
44 static constexpr int32_t FIFTH_PARAM = 4;
45 
46 namespace {
47 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_PRIVACY, "PermissionRecordManagerNapi"};
48 } // namespace
49 
GetJsErrorCode(int32_t errCode)50 static int32_t GetJsErrorCode(int32_t errCode)
51 {
52     int32_t jsCode;
53     switch (errCode) {
54         case RET_SUCCESS:
55             jsCode = JS_OK;
56             break;
57         case ERR_PERMISSION_DENIED:
58             jsCode = JS_ERROR_PERMISSION_DENIED;
59             break;
60         case ERR_NOT_SYSTEM_APP:
61             jsCode = JS_ERROR_NOT_SYSTEM_APP;
62             break;
63         case ERR_PARAM_INVALID:
64             jsCode = JS_ERROR_PARAM_INVALID;
65             break;
66         case ERR_TOKENID_NOT_EXIST:
67             jsCode = JS_ERROR_TOKENID_NOT_EXIST;
68             break;
69         case ERR_PERMISSION_NOT_EXIST:
70             jsCode = JS_ERROR_PERMISSION_NOT_EXIST;
71             break;
72         case ERR_CALLBACK_ALREADY_EXIST:
73         case ERR_CALLBACK_NOT_EXIST:
74         case ERR_PERMISSION_ALREADY_START_USING:
75         case ERR_PERMISSION_NOT_START_USING:
76             jsCode = JS_ERROR_NOT_USE_TOGETHER;
77             break;
78         case ERR_CALLBACKS_EXCEED_LIMITATION:
79             jsCode = JS_ERROR_REGISTERS_EXCEED_LIMITATION;
80             break;
81         case ERR_IDENTITY_CHECK_FAILED:
82             jsCode = JS_ERROR_PERMISSION_OPERATION_NOT_ALLOWED;
83             break;
84         case ERR_SERVICE_ABNORMAL:
85         case ERROR_IPC_REQUEST_FAIL:
86         case ERR_READ_PARCEL_FAILED:
87         case ERR_WRITE_PARCEL_FAILED:
88             jsCode = JS_ERROR_SERVICE_NOT_RUNNING;
89             break;
90         case ERR_MALLOC_FAILED:
91             jsCode = JS_ERROR_OUT_OF_MEMORY;
92             break;
93         default:
94             jsCode = JS_ERROR_INNER;
95             break;
96     }
97     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetJsErrorCode nativeCode(%{public}d) jsCode(%{public}d).", errCode, jsCode);
98     return jsCode;
99 }
100 
ParamResolveErrorThrow(const napi_env & env,const std::string & param,const std::string & type)101 static void ParamResolveErrorThrow(const napi_env& env, const std::string& param, const std::string& type)
102 {
103     std::string errMsg = GetParamErrorMsg(param, type);
104     NAPI_CALL_RETURN_VOID(env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, errMsg)));
105 }
106 
ReturnPromiseResult(napi_env env,const RecordManagerAsyncContext & context,napi_value result)107 static void ReturnPromiseResult(napi_env env, const RecordManagerAsyncContext& context, napi_value result)
108 {
109     if (context.retCode != RET_SUCCESS) {
110         int32_t jsCode = GetJsErrorCode(context.retCode);
111         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
112         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context.deferred, businessError));
113     } else {
114         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context.deferred, result));
115     }
116 }
117 
ReturnCallbackResult(napi_env env,const RecordManagerAsyncContext & context,napi_value result)118 static void ReturnCallbackResult(napi_env env, const RecordManagerAsyncContext& context, napi_value result)
119 {
120     napi_value businessError = GetNapiNull(env);
121     if (context.retCode != RET_SUCCESS) {
122         int32_t jsCode = GetJsErrorCode(context.retCode);
123         businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
124     }
125     napi_value results[ASYNC_CALL_BACK_VALUES_NUM] = { businessError, result };
126 
127     napi_value callback = nullptr;
128     napi_value thisValue = nullptr;
129     napi_value thatValue = nullptr;
130     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &thisValue));
131     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &thatValue));
132     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, context.callbackRef, &callback));
133     NAPI_CALL_RETURN_VOID(env,
134         napi_call_function(env, thisValue, callback, ASYNC_CALL_BACK_VALUES_NUM, results, &thatValue));
135 }
136 
ParseAddPermissionFifthParam(const napi_env env,const napi_value & value,RecordManagerAsyncContext & asyncContext)137 static bool ParseAddPermissionFifthParam(const napi_env env, const napi_value& value,
138     RecordManagerAsyncContext& asyncContext)
139 {
140     napi_valuetype typeValue = napi_undefined;
141     napi_typeof(env, value, &typeValue);
142 
143     if (typeValue == napi_object) {
144         // options
145         napi_value property = nullptr;
146         uint32_t type = 0;
147         /* if AddPermissionUsedRecordOptions exsit valid property, asyncContext.type use input param
148          * if not, asyncContext.type use default NORMAL_TYPE
149          */
150         if (IsNeedParseProperty(env, value, "usedType", property)) {
151             if (!ParseUint32(env, property, type)) {
152                 ParamResolveErrorThrow(env, "AddPermissionUsedRecordOptions:usedType", "number");
153                 return false;
154             }
155 
156             asyncContext.type = static_cast<PermissionUsedType>(type);
157         }
158     } else if (typeValue == napi_function) {
159         // callback
160         if (!IsUndefinedOrNull(env, value) && !ParseCallback(env, value, asyncContext.callbackRef)) {
161             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
162             return false;
163         }
164     }
165 
166     return true;
167 }
168 
ParseAddPermissionRecord(const napi_env env,const napi_callback_info info,RecordManagerAsyncContext & asyncContext)169 static bool ParseAddPermissionRecord(
170     const napi_env env, const napi_callback_info info, RecordManagerAsyncContext& asyncContext)
171 {
172     size_t argc = ADD_PERMISSION_RECORD_MAX_PARAMS;
173     napi_value argv[ADD_PERMISSION_RECORD_MAX_PARAMS] = { nullptr };
174     napi_value thisVar = nullptr;
175     void* data = nullptr;
176 
177     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
178     if (argc < ADD_PERMISSION_RECORD_MIN_PARAMS) {
179         NAPI_CALL_BASE(env,
180             napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
181         return false;
182     }
183 
184     asyncContext.env = env;
185     // 0: the first parameter of argv
186     if (!ParseUint32(env, argv[FIRST_PARAM], asyncContext.tokenId)) {
187         ParamResolveErrorThrow(env, "tokenID", "number");
188         return false;
189     }
190 
191     // 1: the second parameter of argv
192     if (!ParseString(env, argv[SECOND_PARAM], asyncContext.permissionName)) {
193         ParamResolveErrorThrow(env, "permissionName", "string");
194         return false;
195     }
196 
197     // 2: the third parameter of argv
198     if (!ParseInt32(env, argv[THIRD_PARAM], asyncContext.successCount)) {
199         ParamResolveErrorThrow(env, "successCount", "number");
200         return false;
201     }
202 
203     // 3: the fourth parameter of argv
204     if (!ParseInt32(env, argv[FOURTH_PARAM], asyncContext.failCount)) {
205         ParamResolveErrorThrow(env, "failCount", "number");
206         return false;
207     }
208 
209     // 4: the fifth parameter of argv, may be napi_object or napi_function
210     if (argc == ADD_PERMISSION_RECORD_MAX_PARAMS) {
211         if (!ParseAddPermissionFifthParam(env, argv[FIFTH_PARAM], asyncContext)) {
212             return false;
213         }
214     }
215 
216     return true;
217 }
218 
ParseStartAndStopUsingPermission(const napi_env env,const napi_callback_info info,RecordManagerAsyncContext & asyncContext)219 static bool ParseStartAndStopUsingPermission(
220     const napi_env env, const napi_callback_info info, RecordManagerAsyncContext& asyncContext)
221 {
222     size_t argc = START_STOP_MAX_PARAMS;
223     napi_value argv[START_STOP_MAX_PARAMS] = { nullptr };
224     napi_value thisVar = nullptr;
225     void* data = nullptr;
226 
227     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
228     if (argc < START_STOP_MAX_PARAMS - 1) {
229         NAPI_CALL_BASE(env,
230             napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
231         return false;
232     }
233 
234     asyncContext.env = env;
235     // 0: the first parameter of argv
236     if (!ParseUint32(env, argv[0], asyncContext.tokenId)) {
237         ParamResolveErrorThrow(env, "tokenId", "number");
238         return false;
239     }
240 
241     // 1: the second parameter of argv
242     if (!ParseString(env, argv[1], asyncContext.permissionName)) {
243         ParamResolveErrorThrow(env, "permissionName", "string");
244         return false;
245     }
246     if (argc == START_STOP_MAX_PARAMS) {
247         // 2: the third parameter of argv
248         if (!IsUndefinedOrNull(env, argv[2]) && !ParseCallback(env, argv[2], asyncContext.callbackRef)) {
249             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
250             return false;
251         }
252     }
253     return true;
254 }
255 
ConvertDetailUsedRecord(napi_env env,napi_value value,const UsedRecordDetail & detailRecord)256 static void ConvertDetailUsedRecord(napi_env env, napi_value value, const UsedRecordDetail& detailRecord)
257 {
258     napi_value nStatus;
259     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, detailRecord.status, &nStatus));
260     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "status", nStatus));
261 
262     napi_value nLockScreenStatus;
263     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, detailRecord.lockScreenStatus, &nLockScreenStatus));
264     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lockScreenStatus", nLockScreenStatus));
265 
266     napi_value nTimestamp;
267     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, detailRecord.timestamp, &nTimestamp));
268     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "timestamp", nTimestamp));
269 
270     napi_value nAccessDuration;
271     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, detailRecord.accessDuration, &nAccessDuration));
272     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "accessDuration", nAccessDuration));
273 
274     napi_value nCount;
275     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, detailRecord.count, &nCount));
276     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "count", nCount));
277 
278     napi_value nUsedType;
279     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, detailRecord.type, &nUsedType));
280     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "usedType", nUsedType));
281 }
282 
ConvertPermissionUsedRecord(napi_env env,napi_value value,const PermissionUsedRecord & permissionRecord)283 static void ConvertPermissionUsedRecord(napi_env env, napi_value value, const PermissionUsedRecord& permissionRecord)
284 {
285     napi_value nPermissionName;
286     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env,
287         permissionRecord.permissionName.c_str(), NAPI_AUTO_LENGTH, &nPermissionName));
288     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "permissionName", nPermissionName));
289 
290     napi_value nAccessCount;
291     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionRecord.accessCount, &nAccessCount));
292     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "accessCount", nAccessCount));
293 
294     napi_value nRejectCount;
295     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionRecord.rejectCount, &nRejectCount));
296     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "rejectCount", nRejectCount));
297 
298     napi_value nLastAccessTime;
299     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, permissionRecord.lastAccessTime, &nLastAccessTime));
300     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lastAccessTime", nLastAccessTime));
301 
302     napi_value nLastRejectTime;
303     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, permissionRecord.lastRejectTime, &nLastRejectTime));
304     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lastRejectTime", nLastRejectTime));
305 
306     napi_value nLastAccessDuration;
307     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, permissionRecord.lastAccessDuration, &nLastAccessDuration));
308     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "lastAccessDuration", nLastAccessDuration));
309 
310     size_t index = 0;
311     napi_value objAccessRecords;
312     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objAccessRecords));
313     for (const auto& accRecord : permissionRecord.accessRecords) {
314         napi_value objAccessRecord;
315         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objAccessRecord));
316         ConvertDetailUsedRecord(env, objAccessRecord, accRecord);
317         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objAccessRecords, index, objAccessRecord));
318         index++;
319     }
320     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "accessRecords", objAccessRecords));
321 
322     index = 0;
323     napi_value objRejectRecords;
324     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objRejectRecords));
325     for (const auto& rejRecord : permissionRecord.rejectRecords) {
326         napi_value objRejectRecord;
327         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objRejectRecord));
328         ConvertDetailUsedRecord(env, objRejectRecord, rejRecord);
329         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objRejectRecords, index, objRejectRecord));
330         index++;
331     }
332     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "rejectRecords", objRejectRecords));
333 }
334 
ConvertBundleUsedRecord(napi_env env,napi_value value,const BundleUsedRecord & bundleRecord)335 static void ConvertBundleUsedRecord(napi_env env, napi_value value, const BundleUsedRecord& bundleRecord)
336 {
337     napi_value nTokenId;
338     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleRecord.tokenId, &nTokenId));
339     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "tokenId", nTokenId));
340 
341     napi_value nIsRemote;
342     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleRecord.isRemote, &nIsRemote));
343     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "isRemote", nIsRemote));
344 
345     napi_value nDeviceId;
346     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env,
347         bundleRecord.deviceId.c_str(), NAPI_AUTO_LENGTH, &nDeviceId));
348     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "deviceId", nDeviceId));
349 
350     napi_value nBundleName;
351     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env,
352         bundleRecord.bundleName.c_str(), NAPI_AUTO_LENGTH, &nBundleName));
353     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "bundleName", nBundleName));
354     size_t index = 0;
355     napi_value objPermissionRecords;
356     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objPermissionRecords));
357     for (const auto& permRecord : bundleRecord.permissionRecords) {
358         napi_value objPermissionRecord;
359         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objPermissionRecord));
360         ConvertPermissionUsedRecord(env, objPermissionRecord, permRecord);
361         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objPermissionRecords, index, objPermissionRecord));
362         index++;
363     }
364     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "permissionRecords", objPermissionRecords));
365 }
366 
ProcessRecordResult(napi_env env,napi_value value,const PermissionUsedResult & result)367 static void ProcessRecordResult(napi_env env, napi_value value, const PermissionUsedResult& result)
368 {
369     napi_value nBeginTimestamp;
370     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, result.beginTimeMillis, &nBeginTimestamp));
371     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "beginTime", nBeginTimestamp));
372 
373     napi_value nEndTimestamp;
374     NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, result.endTimeMillis, &nEndTimestamp));
375     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "endTime", nEndTimestamp));
376 
377     size_t index = 0;
378     napi_value objBundleRecords;
379     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &objBundleRecords));
380     for (const auto& bundleRecord : result.bundleRecords) {
381         napi_value objBundleRecord;
382         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objBundleRecord));
383         ConvertBundleUsedRecord(env, objBundleRecord, bundleRecord);
384         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objBundleRecords, index, objBundleRecord));
385         index++;
386     }
387     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "bundleRecords", objBundleRecords));
388 }
389 
ParseRequest(const napi_env & env,const napi_value & value,PermissionUsedRequest & request)390 static bool ParseRequest(const napi_env& env, const napi_value& value, PermissionUsedRequest& request)
391 {
392     napi_value property = nullptr;
393     if (IsNeedParseProperty(env, value, "tokenId", property) && !ParseUint32(env, property, request.tokenId)) {
394         ParamResolveErrorThrow(env, "request:tokenId", "number");
395         return false;
396     }
397 
398     if (IsNeedParseProperty(env, value, "isRemote", property) && !ParseBool(env, property, request.isRemote)) {
399         ParamResolveErrorThrow(env, "request:isRemote", "boolean");
400         return false;
401     }
402 
403     if (IsNeedParseProperty(env, value, "deviceId", property) && !ParseString(env, property, request.deviceId)) {
404         ParamResolveErrorThrow(env, "request:deviceId", "string");
405         return false;
406     }
407 
408     if (IsNeedParseProperty(env, value, "bundleName", property) && !ParseString(env, property, request.bundleName)) {
409         ParamResolveErrorThrow(env, "request:bundleName", "string");
410         return false;
411     }
412 
413     if (IsNeedParseProperty(env, value, "beginTime", property) && !ParseInt64(env, property, request.beginTimeMillis)) {
414         ParamResolveErrorThrow(env, "request:beginTime", "number");
415         return false;
416     }
417 
418     if (IsNeedParseProperty(env, value, "endTime", property) && !ParseInt64(env, property, request.endTimeMillis)) {
419         ParamResolveErrorThrow(env, "request:endTime", "number");
420         return false;
421     }
422 
423     if (IsNeedParseProperty(env, value, "permissionNames", property) &&
424         !ParseStringArray(env, property, request.permissionList)) {
425         ParamResolveErrorThrow(env, "request:permissionNames", "Array<string>");
426         return false;
427     }
428 
429     property = nullptr;
430     NAPI_CALL_BASE(env, napi_get_named_property(env, value, "flag", &property), false);
431     int32_t flag;
432     if (!ParseInt32(env, property, flag)) {
433         ParamResolveErrorThrow(env, "request:flag", "number");
434         return false;
435     }
436     request.flag = static_cast<PermissionUsageFlagEnum>(flag);
437     return true;
438 }
439 
ParseGetPermissionUsedRecords(const napi_env env,const napi_callback_info info,RecordManagerAsyncContext & asyncContext)440 static bool ParseGetPermissionUsedRecords(
441     const napi_env env, const napi_callback_info info, RecordManagerAsyncContext& asyncContext)
442 {
443     size_t argc = GET_PERMISSION_RECORD_MAX_PARAMS;
444     napi_value argv[GET_PERMISSION_RECORD_MAX_PARAMS] = { nullptr };
445     napi_value thisVar = nullptr;
446     void* data = nullptr;
447     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
448     if (argc < GET_PERMISSION_RECORD_MAX_PARAMS - 1) {
449         NAPI_CALL_BASE(env,
450             napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
451         return false;
452     }
453 
454     asyncContext.env = env;
455 
456     // 0: the first parameter of argv
457     if (!CheckType(env, argv[0], napi_object)) {
458         ParamResolveErrorThrow(env, "request", "PermissionUsedRequest");
459         return false;
460     }
461     if (!ParseRequest(env, argv[0], asyncContext.request)) {
462         return false;
463     }
464 
465     if (argc == GET_PERMISSION_RECORD_MAX_PARAMS) {
466         // 1: the second parameter of argv
467         if (!IsUndefinedOrNull(env, argv[1]) && !ParseCallback(env, argv[1], asyncContext.callbackRef)) {
468             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
469             return false;
470         }
471     }
472     return true;
473 }
474 
AddPermissionUsedRecordExecute(napi_env env,void * data)475 static void AddPermissionUsedRecordExecute(napi_env env, void* data)
476 {
477     ACCESSTOKEN_LOG_DEBUG(LABEL, "AddPermissionUsedRecord execute.");
478     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
479     if (asyncContext == nullptr) {
480         return;
481     }
482 
483     AddPermParamInfo info;
484     info.tokenId = asyncContext->tokenId;
485     info.permissionName = asyncContext->permissionName;
486     info.successCount = asyncContext->successCount;
487     info.failCount = asyncContext->failCount;
488     info.type = asyncContext->type;
489     asyncContext->retCode = PrivacyKit::AddPermissionUsedRecord(info);
490 }
491 
AddPermissionUsedRecordComplete(napi_env env,napi_status status,void * data)492 static void AddPermissionUsedRecordComplete(napi_env env, napi_status status, void* data)
493 {
494     ACCESSTOKEN_LOG_DEBUG(LABEL, "AddPermissionUsedRecord complete.");
495     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
496     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
497 
498     napi_value result = GetNapiNull(env);
499     if (asyncContext->deferred != nullptr) {
500         ReturnPromiseResult(env, *asyncContext, result);
501     } else {
502         ReturnCallbackResult(env, *asyncContext, result);
503     }
504 }
505 
AddPermissionUsedRecord(napi_env env,napi_callback_info cbinfo)506 napi_value AddPermissionUsedRecord(napi_env env, napi_callback_info cbinfo)
507 {
508     ACCESSTOKEN_LOG_DEBUG(LABEL, "AddPermissionUsedRecord begin.");
509 
510     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
511     if (asyncContext == nullptr) {
512         ACCESSTOKEN_LOG_ERROR(LABEL, "New struct fail.");
513         return nullptr;
514     }
515 
516     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
517     if (!ParseAddPermissionRecord(env, cbinfo, *asyncContext)) {
518         return nullptr;
519     }
520 
521     napi_value result = nullptr;
522     if (asyncContext->callbackRef == nullptr) {
523         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
524     } else {
525         NAPI_CALL(env, napi_get_undefined(env, &result));
526     }
527 
528     napi_value resource = nullptr;
529     NAPI_CALL(env, napi_create_string_utf8(env, "AddPermissionUsedRecord", NAPI_AUTO_LENGTH, &resource));
530 
531     NAPI_CALL(env, napi_create_async_work(env,
532         nullptr,
533         resource,
534         AddPermissionUsedRecordExecute,
535         AddPermissionUsedRecordComplete,
536         reinterpret_cast<void *>(asyncContext),
537         &(asyncContext->asyncWork)));
538     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
539     callbackPtr.release();
540     return result;
541 }
542 
StartUsingPermissionExecute(napi_env env,void * data)543 static void StartUsingPermissionExecute(napi_env env, void* data)
544 {
545     ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission execute.");
546     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
547     if (asyncContext == nullptr) {
548         return;
549     }
550 
551     asyncContext->retCode = PrivacyKit::StartUsingPermission(asyncContext->tokenId,
552         asyncContext->permissionName);
553 }
554 
StartUsingPermissionComplete(napi_env env,napi_status status,void * data)555 static void StartUsingPermissionComplete(napi_env env, napi_status status, void* data)
556 {
557     ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission complete.");
558     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
559     std::unique_ptr<RecordManagerAsyncContext> callbackPtr{asyncContext};
560 
561     napi_value result = GetNapiNull(env);
562     if (asyncContext->deferred != nullptr) {
563         ReturnPromiseResult(env, *asyncContext, result);
564     } else {
565         ReturnCallbackResult(env, *asyncContext, result);
566     }
567 }
568 
StartUsingPermission(napi_env env,napi_callback_info cbinfo)569 napi_value StartUsingPermission(napi_env env, napi_callback_info cbinfo)
570 {
571     ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission begin.");
572     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
573     if (asyncContext == nullptr) {
574         ACCESSTOKEN_LOG_ERROR(LABEL, "New struct fail.");
575         return nullptr;
576     }
577 
578     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
579     if (!ParseStartAndStopUsingPermission(env, cbinfo, *asyncContext)) {
580         return nullptr;
581     }
582 
583     napi_value result = nullptr;
584     if (asyncContext->callbackRef == nullptr) {
585         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
586     } else {
587         NAPI_CALL(env, napi_get_undefined(env, &result));
588     }
589 
590     napi_value resource = nullptr;
591     NAPI_CALL(env, napi_create_string_utf8(env, "StartUsingPermission", NAPI_AUTO_LENGTH, &resource));
592 
593     NAPI_CALL(env, napi_create_async_work(env,
594         nullptr,
595         resource,
596         StartUsingPermissionExecute,
597         StartUsingPermissionComplete,
598         reinterpret_cast<void *>(asyncContext),
599         &(asyncContext->asyncWork)));
600     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
601     callbackPtr.release();
602     return result;
603 }
604 
StopUsingPermissionExecute(napi_env env,void * data)605 static void StopUsingPermissionExecute(napi_env env, void* data)
606 {
607     ACCESSTOKEN_LOG_DEBUG(LABEL, "StopUsingPermission execute.");
608     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
609     if (asyncContext == nullptr) {
610         return;
611     }
612 
613     asyncContext->retCode = PrivacyKit::StopUsingPermission(asyncContext->tokenId,
614         asyncContext->permissionName);
615 }
616 
StopUsingPermissionComplete(napi_env env,napi_status status,void * data)617 static void StopUsingPermissionComplete(napi_env env, napi_status status, void* data)
618 {
619     ACCESSTOKEN_LOG_DEBUG(LABEL, "StopUsingPermission complete.");
620     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
621     std::unique_ptr<RecordManagerAsyncContext> callbackPtr{asyncContext};
622 
623     napi_value result = GetNapiNull(env);
624     if (asyncContext->deferred != nullptr) {
625         ReturnPromiseResult(env, *asyncContext, result);
626     } else {
627         ReturnCallbackResult(env, *asyncContext, result);
628     }
629 }
630 
StopUsingPermission(napi_env env,napi_callback_info cbinfo)631 napi_value StopUsingPermission(napi_env env, napi_callback_info cbinfo)
632 {
633     ACCESSTOKEN_LOG_DEBUG(LABEL, "StopUsingPermission begin.");
634 
635     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
636     if (asyncContext == nullptr) {
637         ACCESSTOKEN_LOG_ERROR(LABEL, "New struct fail.");
638         return nullptr;
639     }
640 
641     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
642     if (!ParseStartAndStopUsingPermission(env, cbinfo, *asyncContext)) {
643         return nullptr;
644     }
645 
646     napi_value result = nullptr;
647     if (asyncContext->callbackRef == nullptr) {
648         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
649     } else {
650         NAPI_CALL(env, napi_get_undefined(env, &result));
651     }
652 
653     napi_value resource = nullptr;
654     NAPI_CALL(env, napi_create_string_utf8(env, "StopUsingPermission", NAPI_AUTO_LENGTH, &resource));
655 
656     NAPI_CALL(env, napi_create_async_work(env,
657         nullptr,
658         resource,
659         StopUsingPermissionExecute,
660         StopUsingPermissionComplete,
661         reinterpret_cast<void *>(asyncContext),
662         &(asyncContext->asyncWork)));
663     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
664     callbackPtr.release();
665     return result;
666 }
667 
GetPermissionUsedRecordsExecute(napi_env env,void * data)668 static void GetPermissionUsedRecordsExecute(napi_env env, void* data)
669 {
670     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedRecords execute.");
671     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
672     if (asyncContext == nullptr) {
673         return;
674     }
675 
676     asyncContext->retCode = PrivacyKit::GetPermissionUsedRecords(asyncContext->request, asyncContext->result);
677 }
678 
GetPermissionUsedRecordsComplete(napi_env env,napi_status status,void * data)679 static void GetPermissionUsedRecordsComplete(napi_env env, napi_status status, void* data)
680 {
681     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedRecords complete.");
682     RecordManagerAsyncContext* asyncContext = reinterpret_cast<RecordManagerAsyncContext*>(data);
683     std::unique_ptr<RecordManagerAsyncContext> callbackPtr{asyncContext};
684 
685     napi_value result = GetNapiNull(env);
686     NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &result));
687     ProcessRecordResult(env, result, asyncContext->result);
688     if (asyncContext->deferred != nullptr) {
689         ReturnPromiseResult(env, *asyncContext, result);
690     } else {
691         ReturnCallbackResult(env, *asyncContext, result);
692     }
693 }
694 
GetPermissionUsedRecords(napi_env env,napi_callback_info cbinfo)695 napi_value GetPermissionUsedRecords(napi_env env, napi_callback_info cbinfo)
696 {
697     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedRecords begin.");
698     auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env);
699     if (asyncContext == nullptr) {
700         ACCESSTOKEN_LOG_ERROR(LABEL, "New struct fail.");
701         return nullptr;
702     }
703 
704     std::unique_ptr<RecordManagerAsyncContext> callbackPtr {asyncContext};
705     if (!ParseGetPermissionUsedRecords(env, cbinfo, *asyncContext)) {
706         return nullptr;
707     }
708 
709     napi_value result = nullptr;
710     if (asyncContext->callbackRef == nullptr) {
711         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
712     } else {
713         NAPI_CALL(env, napi_get_undefined(env, &result));
714     }
715 
716     napi_value resource = nullptr;
717     NAPI_CALL(env, napi_create_string_utf8(env, "GetPermissionUsedRecords", NAPI_AUTO_LENGTH, &resource));
718 
719     NAPI_CALL(env, napi_create_async_work(env,
720         nullptr,
721         resource,
722         GetPermissionUsedRecordsExecute,
723         GetPermissionUsedRecordsComplete,
724         reinterpret_cast<void *>(asyncContext),
725         &(asyncContext->asyncWork)));
726     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
727     callbackPtr.release();
728     return result;
729 }
730 
ParseInputToRegister(const napi_env env,const napi_callback_info cbInfo,RegisterPermActiveChangeContext & registerPermActiveChangeContext)731 static bool ParseInputToRegister(const napi_env env, const napi_callback_info cbInfo,
732     RegisterPermActiveChangeContext& registerPermActiveChangeContext)
733 {
734     size_t argc = ON_OFF_MAX_PARAMS;
735     napi_value argv[ON_OFF_MAX_PARAMS] = {nullptr};
736     napi_value thisVar = nullptr;
737     napi_ref callback = nullptr;
738     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr), false);
739     if (argc < ON_OFF_MAX_PARAMS) {
740         NAPI_CALL_BASE(
741             env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
742         return false;
743     }
744 
745     std::string type;
746     // 0: the first parameter of argv
747     if (!ParseString(env, argv[0], type)) {
748         ParamResolveErrorThrow(env, "type", "string");
749         return false;
750     }
751     std::vector<std::string> permList;
752     // 1: the second parameter of argv
753     if (!ParseStringArray(env, argv[1], permList)) {
754         ParamResolveErrorThrow(env, "permList", "Array<string>");
755         return false;
756     }
757     std::sort(permList.begin(), permList.end());
758     // 2: the third parameter of argv
759     if (!ParseCallback(env, argv[2], callback)) {
760         ParamResolveErrorThrow(env, "callback", "AsyncCallback");
761         return false;
762     }
763     registerPermActiveChangeContext.env = env;
764     registerPermActiveChangeContext.callbackRef = callback;
765     registerPermActiveChangeContext.type = type;
766     registerPermActiveChangeContext.subscriber = std::make_shared<PermActiveStatusPtr>(permList);
767     registerPermActiveChangeContext.subscriber->SetEnv(env);
768     registerPermActiveChangeContext.subscriber->SetCallbackRef(callback);
769     registerPermActiveChangeContext.threadId_ = std::this_thread::get_id();
770     return true;
771 }
772 
ParseInputToUnregister(const napi_env env,const napi_callback_info cbInfo,UnregisterPermActiveChangeContext & unregisterPermActiveChangeContext)773 static bool ParseInputToUnregister(const napi_env env, const napi_callback_info cbInfo,
774     UnregisterPermActiveChangeContext& unregisterPermActiveChangeContext)
775 {
776     size_t argc = ON_OFF_MAX_PARAMS;
777     napi_value argv[ON_OFF_MAX_PARAMS] = {nullptr};
778     napi_value thisVar = nullptr;
779     napi_ref callback = nullptr;
780     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr), false);
781     if (argc < ON_OFF_MAX_PARAMS - 1) {
782         NAPI_CALL_BASE(
783             env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
784         return false;
785     }
786 
787     std::string type;
788     // 0: the first parameter of argv
789     if (!ParseString(env, argv[0], type)) {
790         ParamResolveErrorThrow(env, "permList", "Array<string>");
791         return false;
792     }
793     // 1: the second parameter of argv
794     std::vector<std::string> permList;
795     if (!ParseStringArray(env, argv[1], permList)) {
796         ParamResolveErrorThrow(env, "permList", "Array<string>");
797         return false;
798     }
799     std::sort(permList.begin(), permList.end());
800     if (argc == ON_OFF_MAX_PARAMS) {
801         // 2: the first parameter of argv
802         if (!ParseCallback(env, argv[2], callback)) {
803             ParamResolveErrorThrow(env, "callback", "AsyncCallback");
804             return false;
805         }
806     }
807     unregisterPermActiveChangeContext.env = env;
808     unregisterPermActiveChangeContext.callbackRef = callback;
809     unregisterPermActiveChangeContext.type = type;
810     unregisterPermActiveChangeContext.permList = permList;
811     unregisterPermActiveChangeContext.threadId_ = std::this_thread::get_id();
812     return true;
813 }
814 
IsExistRegister(const PermActiveChangeContext * permActiveChangeContext)815 static bool IsExistRegister(const PermActiveChangeContext* permActiveChangeContext)
816 {
817     std::vector<std::string> targetPermList;
818     permActiveChangeContext->subscriber->GetPermList(targetPermList);
819     std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
820     for (const auto& item : g_permActiveChangeSubscribers) {
821         std::vector<std::string> permList;
822         item->subscriber->GetPermList(permList);
823         bool hasPermIntersection = false;
824         // Special cases:
825         // 1.Have registered full, and then register some
826         // 2.Have registered some, then register full
827         if (permList.empty() || targetPermList.empty()) {
828             hasPermIntersection = true;
829         }
830         for (const auto& PermItem : targetPermList) {
831             if (hasPermIntersection) {
832                 break;
833             }
834             auto iter = std::find(permList.begin(), permList.end(), PermItem);
835             if (iter != permList.end()) {
836                 hasPermIntersection = true;
837             }
838         }
839         if (hasPermIntersection && CompareCallbackRef(permActiveChangeContext->env,
840             item->callbackRef, permActiveChangeContext->callbackRef, item->threadId_)) {
841             return true;
842         }
843     }
844     return false;
845 }
846 
DeleteRegisterInVector(PermActiveChangeContext * permActiveChangeContext)847 static void DeleteRegisterInVector(PermActiveChangeContext* permActiveChangeContext)
848 {
849     std::vector<std::string> targetPermList;
850     permActiveChangeContext->subscriber->GetPermList(targetPermList);
851     std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
852     auto item = g_permActiveChangeSubscribers.begin();
853     while (item != g_permActiveChangeSubscribers.end()) {
854         std::vector<std::string> permList;
855         (*item)->subscriber->GetPermList(permList);
856         if ((permList == targetPermList) && CompareCallbackRef(permActiveChangeContext->env, (*item)->callbackRef,
857             permActiveChangeContext->callbackRef, (*item)->threadId_)) {
858             delete *item;
859             *item = nullptr;
860             g_permActiveChangeSubscribers.erase(item);
861             return;
862         } else {
863             ++item;
864         }
865     }
866 }
867 
FindAndGetSubscriber(UnregisterPermActiveChangeContext * unregisterPermActiveChangeContext,std::vector<RegisterPermActiveChangeContext * > & batchPermActiveChangeSubscribers)868 static bool FindAndGetSubscriber(UnregisterPermActiveChangeContext* unregisterPermActiveChangeContext,
869     std::vector<RegisterPermActiveChangeContext*>& batchPermActiveChangeSubscribers)
870 {
871     std::vector<std::string> targetPermList = unregisterPermActiveChangeContext->permList;
872     std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
873     bool callbackEqual;
874     napi_ref callbackRef = unregisterPermActiveChangeContext->callbackRef;
875     for (const auto& item : g_permActiveChangeSubscribers) {
876         std::vector<std::string> permList;
877         item->subscriber->GetPermList(permList);
878         // targetCallback == nullptr, Unsubscribe from all callbacks under the same permList
879         // targetCallback != nullptr, unregister the subscriber with same permList and callback
880         if (callbackRef == nullptr) {
881             // batch delete currentThread callback
882             callbackEqual = IsCurrentThread(item->threadId_);
883         } else {
884             callbackEqual = CompareCallbackRef(
885                 unregisterPermActiveChangeContext->env, item->callbackRef, callbackRef, item->threadId_);
886         }
887 
888         if ((permList == targetPermList) && callbackEqual) {
889             batchPermActiveChangeSubscribers.emplace_back(item);
890             if (callbackRef != nullptr) {
891                 return true;
892             }
893         }
894     }
895     if (!batchPermActiveChangeSubscribers.empty()) {
896         return true;
897     }
898     return false;
899 }
900 
RegisterPermActiveChangeCallback(napi_env env,napi_callback_info cbInfo)901 napi_value RegisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo)
902 {
903     RegisterPermActiveChangeContext* registerPermActiveChangeContext =
904         new (std::nothrow) RegisterPermActiveChangeContext();
905     if (registerPermActiveChangeContext == nullptr) {
906         ACCESSTOKEN_LOG_ERROR(LABEL, "Insufficient memory for registerPermActiveChangeContext!");
907         return nullptr;
908     }
909     std::unique_ptr<RegisterPermActiveChangeContext> callbackPtr {registerPermActiveChangeContext};
910     if (!ParseInputToRegister(env, cbInfo, *registerPermActiveChangeContext)) {
911         return nullptr;
912     }
913     if (IsExistRegister(registerPermActiveChangeContext)) {
914         ACCESSTOKEN_LOG_ERROR(LABEL, "Subscribe failed. The current subscriber has been existed");
915         std::string errMsg = GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_INVALID);
916         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_INVALID, errMsg)));
917         return nullptr;
918     }
919     int32_t result = PrivacyKit::RegisterPermActiveStatusCallback(registerPermActiveChangeContext->subscriber);
920     if (result != RET_SUCCESS) {
921         ACCESSTOKEN_LOG_ERROR(LABEL, "RegisterPermActiveStatusCallback failed");
922         int32_t jsCode = GetJsErrorCode(result);
923         std::string errMsg = GetErrorMessage(jsCode);
924         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, jsCode, errMsg)));
925         return nullptr;
926     }
927     {
928         std::lock_guard<std::mutex> lock(g_lockForPermActiveChangeSubscribers);
929         if (g_permActiveChangeSubscribers.size() >= MAX_CALLBACK_SIZE) {
930             ACCESSTOKEN_LOG_ERROR(LABEL, "Subscribers size has reached max value");
931             return nullptr;
932         }
933         g_permActiveChangeSubscribers.emplace_back(registerPermActiveChangeContext);
934     }
935     callbackPtr.release();
936     return nullptr;
937 }
938 
UnregisterPermActiveChangeCallback(napi_env env,napi_callback_info cbInfo)939 napi_value UnregisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo)
940 {
941     UnregisterPermActiveChangeContext* unregisterPermActiveChangeContext =
942         new (std::nothrow) UnregisterPermActiveChangeContext();
943     if (unregisterPermActiveChangeContext == nullptr) {
944         ACCESSTOKEN_LOG_ERROR(LABEL, "Insufficient memory for unregisterPermActiveChangeContext!");
945         return nullptr;
946     }
947     std::unique_ptr<UnregisterPermActiveChangeContext> callbackPtr {unregisterPermActiveChangeContext};
948     if (!ParseInputToUnregister(env, cbInfo, *unregisterPermActiveChangeContext)) {
949         return nullptr;
950     }
951     std::vector<RegisterPermActiveChangeContext*> batchPermActiveChangeSubscribers;
952     if (!FindAndGetSubscriber(unregisterPermActiveChangeContext, batchPermActiveChangeSubscribers)) {
953         ACCESSTOKEN_LOG_ERROR(LABEL, "Unsubscribe failed. The current subscriber does not exist");
954         std::string errMsg = GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_INVALID);
955         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_INVALID, errMsg)));
956         return nullptr;
957     }
958     for (const auto& item : batchPermActiveChangeSubscribers) {
959         int32_t result = PrivacyKit::UnRegisterPermActiveStatusCallback(item->subscriber);
960         if (result == RET_SUCCESS) {
961             DeleteRegisterInVector(item);
962         } else {
963             ACCESSTOKEN_LOG_ERROR(LABEL, "UnregisterPermActiveChangeCompleted failed");
964             int32_t jsCode = GetJsErrorCode(result);
965             std::string errMsg = GetErrorMessage(jsCode);
966             NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, jsCode, errMsg)));
967         }
968     }
969     return nullptr;
970 }
971 
ParseGetPermissionUsedType(const napi_env env,const napi_callback_info cbInfo,PermissionUsedTypeAsyncContext & context)972 static bool ParseGetPermissionUsedType(const napi_env env, const napi_callback_info cbInfo,
973     PermissionUsedTypeAsyncContext& context)
974 {
975     size_t argc = GET_PERMISSION_USED_TYPE_MAX_PARAMS;
976     napi_value argv[GET_PERMISSION_USED_TYPE_MAX_PARAMS] = {nullptr};
977     napi_value thisVar = nullptr;
978     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr), false);
979 
980     AccessTokenID tokenId = 0;
981     std::string permissionName;
982 
983     if (argc == GET_PERMISSION_USED_TYPE_ONE_PARAMS) {
984         // one param: only tokenId
985         if (!ParseUint32(env, argv[0], tokenId)) {
986             ParamResolveErrorThrow(env, "tokenId", "number");
987             return false;
988         }
989     } else if (argc == GET_PERMISSION_USED_TYPE_MAX_PARAMS) {
990         // two params: tokenId + permissionName or null + permissionName
991         if (!IsUndefinedOrNull(env, argv[0])) {
992             // if first param is null, ignore it, otherwise that is tokenId: number
993             if (!ParseUint32(env, argv[0], tokenId)) {
994                 ParamResolveErrorThrow(env, "tokenId", "number");
995                 return false;
996             }
997         }
998 
999         if (!ParseString(env, argv[1], permissionName)) {
1000             ParamResolveErrorThrow(env, "permissionName", "string");
1001             return false;
1002         }
1003     }
1004 
1005     // if there is no input param, that means return all tokenId and permissionName
1006     context.env = env;
1007     context.tokenId = tokenId;
1008     context.permissionName = permissionName;
1009     return true;
1010 }
1011 
GetPermissionUsedTypeInfosExecute(napi_env env,void * data)1012 static void GetPermissionUsedTypeInfosExecute(napi_env env, void* data)
1013 {
1014     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionUsedTypeInfos execute.");
1015 
1016     PermissionUsedTypeAsyncContext* asyncContext = reinterpret_cast<PermissionUsedTypeAsyncContext*>(data);
1017     if (asyncContext == nullptr) {
1018         return;
1019     }
1020 
1021     asyncContext->retCode = PrivacyKit::GetPermissionUsedTypeInfos(asyncContext->tokenId, asyncContext->permissionName,
1022         asyncContext->results);
1023 }
1024 
ConvertPermissionUsedTypeInfo(const napi_env & env,napi_value & value,const PermissionUsedTypeInfo & info)1025 static void ConvertPermissionUsedTypeInfo(const napi_env& env, napi_value& value, const PermissionUsedTypeInfo& info)
1026 {
1027     napi_value tokenIdValue;
1028     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, info.tokenId, &tokenIdValue));
1029     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "tokenId", tokenIdValue));
1030 
1031     napi_value permissionNameValue;
1032     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, info.permissionName.c_str(),
1033         NAPI_AUTO_LENGTH, &permissionNameValue));
1034     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "permissionName", permissionNameValue));
1035 
1036     napi_value permissionUsedTypeValue;
1037     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, info.type, &permissionUsedTypeValue));
1038     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "usedType", permissionUsedTypeValue));
1039 }
1040 
ProcessPermissionUsedTypeInfoResult(const napi_env & env,napi_value & value,const std::vector<PermissionUsedTypeInfo> & results)1041 static void ProcessPermissionUsedTypeInfoResult(const napi_env& env, napi_value& value,
1042     const std::vector<PermissionUsedTypeInfo>& results)
1043 {
1044     ACCESSTOKEN_LOG_INFO(LABEL, "Size is %{public}zu", results.size());
1045     size_t index = 0;
1046     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &value));
1047     for (const auto& result : results) {
1048         napi_value permissionUsedTypeValue;
1049         NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &permissionUsedTypeValue));
1050         ConvertPermissionUsedTypeInfo(env, permissionUsedTypeValue, result);
1051         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, value, index, permissionUsedTypeValue));
1052         index++;
1053     }
1054 }
1055 
GetPermissionUsedTypeInfosComplete(napi_env env,napi_status status,void * data)1056 static void GetPermissionUsedTypeInfosComplete(napi_env env, napi_status status, void* data)
1057 {
1058     ACCESSTOKEN_LOG_INFO(LABEL, "GetPermissionUsedTypeInfos complete.");
1059 
1060     PermissionUsedTypeAsyncContext* asyncContext = reinterpret_cast<PermissionUsedTypeAsyncContext*>(data);
1061     std::unique_ptr<PermissionUsedTypeAsyncContext> callbackPtr{asyncContext};
1062 
1063     napi_value result = GetNapiNull(env);
1064     NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &result));
1065     ProcessPermissionUsedTypeInfoResult(env, result, asyncContext->results);
1066 
1067     if (asyncContext->retCode != RET_SUCCESS) {
1068         int32_t jsCode = GetJsErrorCode(asyncContext->retCode);
1069         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
1070         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncContext->deferred, businessError));
1071     } else {
1072         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncContext->deferred, result));
1073     }
1074 }
1075 
GetPermissionUsedTypeInfos(napi_env env,napi_callback_info cbinfo)1076 napi_value GetPermissionUsedTypeInfos(napi_env env, napi_callback_info cbinfo)
1077 {
1078     ACCESSTOKEN_LOG_INFO(LABEL, "GetPermissionUsedTypeInfos begin.");
1079 
1080     auto *asyncContext = new (std::nothrow) PermissionUsedTypeAsyncContext(env);
1081     if (asyncContext == nullptr) {
1082         ACCESSTOKEN_LOG_ERROR(LABEL, "New struct fail.");
1083         return nullptr;
1084     }
1085 
1086     std::unique_ptr<PermissionUsedTypeAsyncContext> callbackPtr {asyncContext};
1087     if (!ParseGetPermissionUsedType(env, cbinfo, *asyncContext)) {
1088         return nullptr;
1089     }
1090 
1091     napi_value result = nullptr;
1092     NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
1093 
1094     napi_value resource = nullptr;
1095     NAPI_CALL(env, napi_create_string_utf8(env, "GetPermissionUsedTypeInfos", NAPI_AUTO_LENGTH, &resource));
1096 
1097     NAPI_CALL(env, napi_create_async_work(env,
1098         nullptr,
1099         resource,
1100         GetPermissionUsedTypeInfosExecute,
1101         GetPermissionUsedTypeInfosComplete,
1102         reinterpret_cast<void *>(asyncContext),
1103         &(asyncContext->asyncWork)));
1104     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->asyncWork, napi_qos_default));
1105     callbackPtr.release();
1106     return result;
1107 }
1108 }  // namespace AccessToken
1109 }  // namespace Security
1110 }  // namespace OHOS