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