• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "privacy_manager.h"
17 
18 #include <iostream>
19 
20 #include "accesstoken_common_log.h"
21 #include "ani_error.h"
22 #include "ani_utils.h"
23 #include "privacy_error.h"
24 #include "privacy_kit.h"
25 
26 namespace OHOS {
27 namespace Security {
28 namespace AccessToken {
29 namespace {
30 std::mutex g_mutex;
31 std::vector<RegisterPermActiveChangeContext*> g_subScribers;
32 static constexpr size_t MAX_CALLBACK_SIZE = 200;
33 constexpr const char* ACTIVE_CHANGE_FIELD_CALLING_TOKEN_ID = "callingTokenId";
34 constexpr const char* ACTIVE_CHANGE_FIELD_TOKEN_ID = "tokenId";
35 constexpr const char* ACTIVE_CHANGE_FIELD_PERMISSION_NAME = "permissionName";
36 constexpr const char* ACTIVE_CHANGE_FIELD_DEVICE_ID = "deviceId";
37 constexpr const char* ACTIVE_CHANGE_FIELD_ACTIVE_STATUS = "activeStatus";
38 constexpr const char* ACTIVE_CHANGE_FIELD_USED_TYPE = "usedType";
39 }
40 
GetStsErrorCode(int32_t errCode)41 static int32_t GetStsErrorCode(int32_t errCode)
42 {
43     int32_t stsCode;
44     switch (errCode) {
45         case RET_SUCCESS:
46             stsCode = STS_OK;
47             break;
48         case ERR_PERMISSION_DENIED:
49             stsCode = STS_ERROR_PERMISSION_DENIED;
50             break;
51         case ERR_NOT_SYSTEM_APP:
52             stsCode = STS_ERROR_NOT_SYSTEM_APP;
53             break;
54         case ERR_PARAM_INVALID:
55             stsCode = STS_ERROR_PARAM_INVALID;
56             break;
57         case ERR_TOKENID_NOT_EXIST:
58             stsCode = STS_ERROR_TOKENID_NOT_EXIST;
59             break;
60         case ERR_PERMISSION_NOT_EXIST:
61             stsCode = STS_ERROR_PERMISSION_NOT_EXIST;
62             break;
63         case ERR_CALLBACK_ALREADY_EXIST:
64         case ERR_CALLBACK_NOT_EXIST:
65         case ERR_PERMISSION_ALREADY_START_USING:
66         case ERR_PERMISSION_NOT_START_USING:
67             stsCode = STS_ERROR_NOT_USE_TOGETHER;
68             break;
69         case ERR_CALLBACKS_EXCEED_LIMITATION:
70             stsCode = STS_ERROR_REGISTERS_EXCEED_LIMITATION;
71             break;
72         case ERR_IDENTITY_CHECK_FAILED:
73             stsCode = STS_ERROR_PERMISSION_OPERATION_NOT_ALLOWED;
74             break;
75         case ERR_SERVICE_ABNORMAL:
76         case ERROR_IPC_REQUEST_FAIL:
77         case ERR_READ_PARCEL_FAILED:
78         case ERR_WRITE_PARCEL_FAILED:
79             stsCode = STS_ERROR_SERVICE_NOT_RUNNING;
80             break;
81         case ERR_MALLOC_FAILED:
82             stsCode = STS_ERROR_OUT_OF_MEMORY;
83             break;
84         default:
85             stsCode = STS_ERROR_INNER;
86             break;
87     }
88     LOGD(PRI_DOMAIN, PRI_TAG, "GetStsErrorCode nativeCode(%{public}d) stsCode(%{public}d).", errCode, stsCode);
89     return stsCode;
90 }
91 
AddPermissionUsedRecordExecute(ani_env * env,ani_int aniTokenID,ani_string aniPermission,ani_int successCount,ani_int failCount,ani_object options)92 static void AddPermissionUsedRecordExecute([[maybe_unused]] ani_env* env,
93     ani_int aniTokenID, ani_string aniPermission, ani_int successCount, ani_int failCount, ani_object options)
94 {
95     if (env == nullptr) {
96         return;
97     }
98     AccessTokenID tokenID = static_cast<AccessTokenID>(aniTokenID);
99     std::string permission = ParseAniString(env, aniPermission);
100     if ((!BusinessErrorAni::ValidateTokenIDWithThrowError(env, tokenID)) ||
101         (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permission))) {
102         LOGE(PRI_DOMAIN, PRI_TAG, "TokenId(%{public}u) or Permission(%{public}s) is invalid.",
103             tokenID, permission.c_str());
104         return;
105     }
106 
107     int32_t usedType = 0;
108     if (!GetEnumProperty(env, options, "usedType", usedType)) {
109         return;
110     }
111     AddPermParamInfo info;
112     info.tokenId = static_cast<AccessTokenID>(tokenID);
113     info.permissionName = permission;
114     info.successCount = successCount;
115     info.failCount = failCount;
116     info.type = static_cast<PermissionUsedType>(usedType);
117     auto retCode = PrivacyKit::AddPermissionUsedRecord(info);
118     if (retCode != RET_SUCCESS) {
119         int32_t stsCode = GetStsErrorCode(retCode);
120         BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
121         return;
122     }
123 }
124 
PermActiveStatusPtr(const std::vector<std::string> & permList)125 PermActiveStatusPtr::PermActiveStatusPtr(const std::vector<std::string>& permList)
126     : PermActiveStatusCustomizedCbk(permList)
127 {}
128 
~PermActiveStatusPtr()129 PermActiveStatusPtr::~PermActiveStatusPtr()
130 {
131     if (vm_ == nullptr) {
132         LOGE(PRI_DOMAIN, PRI_TAG, "Vm is null.");
133         return;
134     }
135     bool isSameThread = (threadId_ == std::this_thread::get_id());
136     ani_env* env = isSameThread ? env_ : GetCurrentEnv(vm_);
137     if (env == nullptr) {
138         LOGE(PRI_DOMAIN, PRI_TAG, "Current env is null.");
139     } else if (ref_ != nullptr) {
140         env->GlobalReference_Delete(ref_);
141     }
142     ref_ = nullptr;
143 
144     if (!isSameThread) {
145         vm_->DetachCurrentThread();
146     }
147 }
148 
SetVm(ani_vm * vm)149 void PermActiveStatusPtr::SetVm(ani_vm* vm)
150 {
151     vm_ = vm;
152 }
153 
SetEnv(ani_env * env)154 void PermActiveStatusPtr::SetEnv(ani_env* env)
155 {
156     env_ = env;
157 }
158 
SetCallbackRef(const ani_ref & ref)159 void PermActiveStatusPtr::SetCallbackRef(const ani_ref& ref)
160 {
161     ref_ = ref;
162 }
163 
SetThreadId(const std::thread::id threadId)164 void PermActiveStatusPtr::SetThreadId(const std::thread::id threadId)
165 {
166     threadId_ = threadId;
167 }
168 
ConvertActiveChangeResponse(ani_env * env,const ActiveChangeResponse & result)169 static ani_object ConvertActiveChangeResponse(ani_env* env, const ActiveChangeResponse& result)
170 {
171     ani_object aniObject = CreateClassObject(env, "L@ohos/privacyManager/privacyManager/ActiveChangeResponseInner;");
172     if (aniObject == nullptr) {
173         return nullptr;
174     }
175 
176     // set callingTokenID?: int  optional parameter callingTokenID need box as a object
177     SetIntProperty(env, aniObject, ACTIVE_CHANGE_FIELD_CALLING_TOKEN_ID, static_cast<int32_t>(result.callingTokenID));
178 
179     // set tokenID: int
180     SetIntProperty(env, aniObject, ACTIVE_CHANGE_FIELD_TOKEN_ID, static_cast<int32_t>(result.tokenID));
181 
182     // set permissionName: string
183     SetStringProperty(env, aniObject, ACTIVE_CHANGE_FIELD_PERMISSION_NAME, result.permissionName);
184 
185     // set deviceId: string
186     SetStringProperty(env, aniObject, ACTIVE_CHANGE_FIELD_DEVICE_ID, result.deviceId);
187 
188     // set activeStatus: PermissionActiveStatus
189     const char* activeStatusDes = "L@ohos/privacyManager/privacyManager/PermissionActiveStatus;";
190     SetEnumProperty(
191         env, aniObject, activeStatusDes, ACTIVE_CHANGE_FIELD_ACTIVE_STATUS, static_cast<uint32_t>(result.type));
192 
193     // set usedType?: PermissionUsedType
194     const char* permUsedTypeDes = "L@ohos/privacyManager/privacyManager/PermissionUsedType;";
195     SetEnumProperty(
196         env, aniObject, permUsedTypeDes, ACTIVE_CHANGE_FIELD_USED_TYPE, static_cast<uint32_t>(result.usedType));
197     return aniObject;
198 }
199 
ActiveStatusChangeCallback(ActiveChangeResponse & activeChangeResponse)200 void PermActiveStatusPtr::ActiveStatusChangeCallback(ActiveChangeResponse& activeChangeResponse)
201 {
202     if (vm_ == nullptr) {
203         LOGE(PRI_DOMAIN, PRI_TAG, "Vm is null.");
204         return;
205     }
206 
207     ani_option interopEnabled {"--interop=disable", nullptr};
208     ani_options aniArgs {1, &interopEnabled};
209     ani_env* env;
210     if (vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env) != ANI_OK) {
211         LOGE(PRI_DOMAIN, PRI_TAG, "AttachCurrentThread failed!");
212         return;
213     }
214 
215     ani_fn_object fnObj = reinterpret_cast<ani_fn_object>(ref_);
216     if (fnObj == nullptr) {
217         LOGE(PRI_DOMAIN, PRI_TAG, "Reinterpret_cast failed!");
218         return;
219     }
220 
221     ani_object aniObject = ConvertActiveChangeResponse(env, activeChangeResponse);
222     if (aniObject == nullptr) {
223         LOGE(PRI_DOMAIN, PRI_TAG, "Convert object is null.");
224         return;
225     }
226     std::vector<ani_ref> args;
227     args.emplace_back(aniObject);
228     ani_ref result;
229     if (!AniFunctionalObjectCall(env, fnObj, args.size(), args.data(), result)) {
230         return;
231     }
232 
233     if (vm_->DetachCurrentThread() != ANI_OK) {
234         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to DetachCurrentThread!");
235         return;
236     }
237 }
238 
ParseInputToRegister(const ani_string & aniType,const ani_array_ref & aniArray,const ani_ref & aniCallback,RegisterPermActiveChangeContext * context,bool isReg)239 static bool ParseInputToRegister(const ani_string& aniType, const ani_array_ref& aniArray,
240     const ani_ref& aniCallback, RegisterPermActiveChangeContext* context, bool isReg)
241 {
242     std::string type = ParseAniString(context->env, static_cast<ani_string>(aniType));
243     std::vector<std::string> permList = ParseAniStringVector(context->env, aniArray);
244     std::sort(permList.begin(), permList.end());
245 
246     bool hasCallback = true;
247     if (!isReg) {
248         hasCallback = !AniIsRefUndefined(context->env, aniCallback);
249     }
250 
251     ani_ref callback = nullptr; // callback: the third parameter is function
252     if (hasCallback) {
253         if (!AniParseCallback(context->env, aniCallback, callback)) {
254             BusinessErrorAni::ThrowParameterTypeError(
255                 context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg("callback", "Callback"));
256             return false;
257         }
258     }
259 
260     ani_vm* vm;
261     if (context->env->GetVM(&vm) != ANI_OK) {
262         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to GetVM!");
263         return false;
264     }
265 
266     context->callbackRef = callback;
267     context->type = type;
268     context->permissionList = permList;
269     context->subscriber = std::make_shared<PermActiveStatusPtr>(permList);
270     context->threadId = std::this_thread::get_id();
271 
272     context->subscriber->SetVm(vm);
273     context->subscriber->SetEnv(context->env);
274     context->subscriber->SetCallbackRef(callback);
275     context->subscriber->SetThreadId(context->threadId);
276 
277     return true;
278 }
279 
IsExistRegister(const RegisterPermActiveChangeContext * context)280 static bool IsExistRegister(const RegisterPermActiveChangeContext* context)
281 {
282     std::vector<std::string> targetPermList;
283     context->subscriber->GetPermList(targetPermList);
284     std::lock_guard<std::mutex> lock(g_mutex);
285     for (const auto& item : g_subScribers) {
286         std::vector<std::string> permList;
287         item->subscriber->GetPermList(permList);
288         bool hasPermIntersection = false;
289         // Special cases:
290         // 1.Have registered full, and then register some
291         // 2.Have registered some, then register full
292         if (permList.empty() || targetPermList.empty()) {
293             hasPermIntersection = true;
294         }
295         for (const auto& PermItem : targetPermList) {
296             if (hasPermIntersection) {
297                 break;
298             }
299             auto iter = std::find(permList.begin(), permList.end(), PermItem);
300             if (iter != permList.end()) {
301                 hasPermIntersection = true;
302             }
303         }
304         bool isEqual = true;
305         if (!AniIsCallbackRefEqual(context->env, item->callbackRef, context->callbackRef, item->threadId, isEqual)) {
306             return true;
307         }
308         if (hasPermIntersection && isEqual) {
309             return true;
310         }
311     }
312     return false;
313 }
314 
RegisterPermActiveStatusCallback(ani_env * env,ani_string aniType,ani_array_ref aniArray,ani_ref callback)315 static void RegisterPermActiveStatusCallback([[maybe_unused]] ani_env* env,
316     ani_string aniType, ani_array_ref aniArray, ani_ref callback)
317 {
318     if (env == nullptr) {
319         return;
320     }
321 
322     RegisterPermActiveChangeContext* context = new (std::nothrow) RegisterPermActiveChangeContext();
323     if (context == nullptr) {
324         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to allocate memory for RegisterPermActiveChangeContext!");
325         return;
326     }
327     context->env = env;
328     std::unique_ptr<RegisterPermActiveChangeContext> callbackPtr {context};
329 
330     if (!ParseInputToRegister(aniType, aniArray, callback, context, true)) {
331         return;
332     }
333 
334     if (IsExistRegister(context)) {
335         std::string errMsg = GetErrorMessage(
336             STS_ERROR_NOT_USE_TOGETHER, "The API reuses the same input. The subscriber already exists.");
337         BusinessErrorAni::ThrowError(
338             env, STS_ERROR_NOT_USE_TOGETHER, GetErrorMessage(STS_ERROR_NOT_USE_TOGETHER, errMsg));
339         return;
340     }
341 
342     int32_t result = PrivacyKit::RegisterPermActiveStatusCallback(context->subscriber);
343     if (result != RET_SUCCESS) {
344         LOGE(PRI_DOMAIN, PRI_TAG, "RegisterPermActiveStatusCallback failed, res is %{public}d.", result);
345         int32_t stsCode = GetStsErrorCode(result);
346         BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
347         return;
348     }
349 
350     {
351         std::lock_guard<std::mutex> lock(g_mutex);
352         if (g_subScribers.size() >= MAX_CALLBACK_SIZE) {
353             LOGE(PRI_DOMAIN, PRI_TAG, "Subscribers size has reached the max %{public}zu.", MAX_CALLBACK_SIZE);
354             BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_REGISTERS_EXCEED_LIMITATION,
355                 GetErrorMessage(STSErrorCode::STS_ERROR_REGISTERS_EXCEED_LIMITATION));
356             return;
357         }
358         g_subScribers.emplace_back(context);
359     }
360 
361     callbackPtr.release();
362     LOGI(PRI_DOMAIN, PRI_TAG, "RegisterPermActiveStatusCallback success!");
363     return;
364 }
365 
FindAndGetSubscriber(const RegisterPermActiveChangeContext * context,std::vector<RegisterPermActiveChangeContext * > & batchPermActiveChangeSubscribers)366 static bool FindAndGetSubscriber(const RegisterPermActiveChangeContext* context,
367     std::vector<RegisterPermActiveChangeContext*>& batchPermActiveChangeSubscribers)
368 {
369     std::vector<std::string> targetPermList = context->permissionList;
370     std::lock_guard<std::mutex> lock(g_mutex);
371     bool callbackEqual;
372     ani_ref callbackRef = context->callbackRef;
373     bool isUndef = AniIsRefUndefined(context->env, context->callbackRef);
374     for (const auto& item : g_subScribers) {
375         std::vector<std::string> permList;
376         item->subscriber->GetPermList(permList);
377         // targetCallback == nullptr, Unsubscribe from all callbacks under the same permList
378         // targetCallback != nullptr, unregister the subscriber with same permList and callback
379         if (isUndef) {
380             // batch delete currentThread callback
381             LOGI(PRI_DOMAIN, PRI_TAG, "Callback is null.");
382             callbackEqual = IsCurrentThread(item->threadId);
383         } else {
384             LOGI(PRI_DOMAIN, PRI_TAG, "Compare callback.");
385             if (!AniIsCallbackRefEqual(context->env, item->callbackRef, callbackRef, item->threadId, callbackEqual)) {
386                 continue;
387             }
388         }
389 
390         if (callbackEqual && (permList == targetPermList)) {
391             batchPermActiveChangeSubscribers.emplace_back(item);
392             if (!isUndef) {
393                 return true;
394             }
395         }
396     }
397     return !batchPermActiveChangeSubscribers.empty();
398 }
399 
DeleteRegisterInVector(const RegisterPermActiveChangeContext * context)400 static void DeleteRegisterInVector(const RegisterPermActiveChangeContext* context)
401 {
402     std::vector<std::string> targetPermList;
403     context->subscriber->GetPermList(targetPermList);
404     std::lock_guard<std::mutex> lock(g_mutex);
405     auto item = g_subScribers.begin();
406     while (item != g_subScribers.end()) {
407         bool isEqual = true;
408         if (!AniIsCallbackRefEqual(
409             context->env, (*item)->callbackRef, context->callbackRef, (*item)->threadId, isEqual)) {
410             continue;
411         }
412         if (!isEqual) {
413             continue;
414         }
415 
416         std::vector<std::string> permList;
417         (*item)->subscriber->GetPermList(permList);
418         if (permList == targetPermList) {
419             delete *item;
420             *item = nullptr;
421             g_subScribers.erase(item);
422             return;
423         } else {
424             ++item;
425         }
426     }
427 }
428 
UnRegisterPermActiveStatusCallback(ani_env * env,ani_string aniType,ani_array_ref aniArray,ani_ref callback)429 static void UnRegisterPermActiveStatusCallback([[maybe_unused]] ani_env* env,
430     ani_string aniType, ani_array_ref aniArray, ani_ref callback)
431 {
432     if (env == nullptr) {
433         return;
434     }
435 
436     RegisterPermActiveChangeContext* context = new (std::nothrow) RegisterPermActiveChangeContext();
437     if (context == nullptr) {
438         return;
439     }
440     context->env = env;
441     std::unique_ptr<RegisterPermActiveChangeContext> callbackPtr {context};
442     if (!ParseInputToRegister(aniType, aniArray, callback, context, false)) {
443         return;
444     }
445 
446     std::vector<RegisterPermActiveChangeContext*> batchPermActiveChangeSubscribers;
447     if (!FindAndGetSubscriber(context, batchPermActiveChangeSubscribers)) {
448         std::string errMsg = GetErrorMessage(
449             STS_ERROR_NOT_USE_TOGETHER, "The API is not used in pair with 'on'. The subscriber does not exist.");
450         BusinessErrorAni::ThrowError(
451             env, STS_ERROR_NOT_USE_TOGETHER, GetErrorMessage(STS_ERROR_NOT_USE_TOGETHER, errMsg));
452         return;
453     }
454 
455     for (const auto& item : batchPermActiveChangeSubscribers) {
456         int32_t result = PrivacyKit::UnRegisterPermActiveStatusCallback(item->subscriber);
457         if (result == RET_SUCCESS) {
458             DeleteRegisterInVector(item);
459         } else {
460             LOGE(PRI_DOMAIN, PRI_TAG, "Failed to UnregisterPermActiveChangeCompleted.");
461             int32_t stsCode = GetStsErrorCode(result);
462             BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
463         }
464     }
465     LOGI(PRI_DOMAIN, PRI_TAG, "UnRegisterPermActiveStatusCallback success!");
466     return;
467 }
468 
StopUsingPermissionExecute(ani_env * env,ani_int aniTokenID,ani_string aniPermission,ani_int pid)469 static void StopUsingPermissionExecute(
470     [[maybe_unused]] ani_env* env, ani_int aniTokenID, ani_string aniPermission, ani_int pid)
471 {
472     LOGI(PRI_DOMAIN, PRI_TAG, "StopUsingPermissionExecute begin.");
473     if (env == nullptr) {
474         LOGE(PRI_DOMAIN, PRI_TAG, "Env is null.");
475         return;
476     }
477 
478     AccessTokenID tokenID = static_cast<AccessTokenID>(aniTokenID);
479     std::string permission = ParseAniString(env, aniPermission);
480     if ((!BusinessErrorAni::ValidateTokenIDWithThrowError(env, tokenID)) ||
481         (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permission))) {
482         LOGE(PRI_DOMAIN, PRI_TAG, "TokenId(%{public}u) or Permission(%{public}s) is invalid.",
483             tokenID, permission.c_str());
484         return;
485     }
486 
487     LOGI(PRI_DOMAIN, PRI_TAG, "PermissionName : %{public}s, tokenID : %{public}u, pid : %{public}d.",
488         permission.c_str(), tokenID, pid);
489 
490     auto retCode = PrivacyKit::StopUsingPermission(tokenID, permission, pid);
491     if (retCode != RET_SUCCESS) {
492         int32_t stsCode = GetStsErrorCode(retCode);
493         BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
494     }
495 }
496 
StartUsingPermissionExecute(ani_env * env,ani_int aniTokenID,ani_string aniPermission,ani_int pid,PermissionUsedType usedType)497 static void StartUsingPermissionExecute([[maybe_unused]] ani_env* env,
498     ani_int aniTokenID, ani_string aniPermission, ani_int pid, PermissionUsedType usedType)
499 {
500     LOGI(PRI_DOMAIN, PRI_TAG, "StartUsingPermissionExecute begin.");
501     if (env == nullptr) {
502         LOGE(PRI_DOMAIN, PRI_TAG, "Env is null.");
503         return;
504     }
505     AccessTokenID tokenID = static_cast<AccessTokenID>(aniTokenID);
506     std::string permission = ParseAniString(env, aniPermission);
507     if ((!BusinessErrorAni::ValidateTokenIDWithThrowError(env, tokenID)) ||
508         (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permission))) {
509         LOGE(PRI_DOMAIN, PRI_TAG, "TokenId(%{public}u) or Permission(%{public}s) is invalid.",
510             tokenID, permission.c_str());
511         return;
512     }
513 
514     LOGI(PRI_DOMAIN, PRI_TAG, "PermissionName : %{public}s, tokenID : %{public}u, pid : %{public}d.",
515         permission.c_str(), tokenID, pid);
516 
517     auto retCode = PrivacyKit::StartUsingPermission(tokenID, permission, pid, usedType);
518     if (retCode != RET_SUCCESS) {
519         int32_t stsCode = GetStsErrorCode(retCode);
520         BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
521     }
522 }
523 
ConvertSingleUsedRecordDetail(ani_env * env,const UsedRecordDetail & record)524 static ani_object ConvertSingleUsedRecordDetail(ani_env* env, const UsedRecordDetail& record)
525 {
526     ani_object arrayObj = CreateClassObject(env, "L@ohos/privacyManager/privacyManager/UsedRecordDetailInner;");
527     if (arrayObj == nullptr) {
528         return nullptr;
529     }
530     if (!SetIntProperty(env, arrayObj, "status", record.status)) {
531         return nullptr;
532     }
533     if (!SetOptionalIntProperty(env, arrayObj, "lockScreenStatus", record.lockScreenStatus)) {
534         return nullptr;
535     }
536     if (!SetLongProperty(env, arrayObj, "timestamp", record.timestamp)) {
537         return nullptr;
538     }
539     if (!SetLongProperty(env, arrayObj, "accessDuration", record.accessDuration)) {
540         return nullptr;
541     }
542     if (!SetOptionalIntProperty(env, arrayObj, "count", record.count)) {
543         return nullptr;
544     }
545     if (!SetEnumProperty(env, arrayObj, "L@ohos/privacyManager/privacyManager/PermissionUsedType;", "usedType",
546         static_cast<uint32_t>(record.type))) {
547         return nullptr;
548     }
549     return arrayObj;
550 }
551 
ConvertUsedRecordDetails(ani_env * env,const std::vector<UsedRecordDetail> & details)552 static ani_object ConvertUsedRecordDetails(ani_env* env, const std::vector<UsedRecordDetail>& details)
553 {
554     ani_object arrayObj = CreateArrayObject(env, details.size());
555     if (arrayObj == nullptr) {
556         return nullptr;
557     }
558     ani_size index = 0;
559     for (const auto& record: details) {
560         ani_ref aniRecord = ConvertSingleUsedRecordDetail(env, record);
561         if (aniRecord == nullptr) {
562             LOGE(PRI_DOMAIN, PRI_TAG, "aniRecord is null.");
563             break;
564         }
565         ani_status status = env->Object_CallMethodByName_Void(
566             arrayObj, "$_set", "ILstd/core/Object;:V", index, aniRecord);
567         if (status != ANI_OK) {
568             LOGE(PRI_DOMAIN, PRI_TAG, "status : %{public}d.", status);
569             break;
570         }
571         ++index;
572     }
573     return arrayObj;
574 }
575 
ConvertSinglePermissionRecord(ani_env * env,const PermissionUsedRecord & record)576 static ani_object ConvertSinglePermissionRecord(ani_env* env, const PermissionUsedRecord& record)
577 {
578     ani_object arrayObj = CreateClassObject(env, "L@ohos/privacyManager/privacyManager/PermissionUsedRecordInner;");
579     if (arrayObj == nullptr) {
580         return nullptr;
581     }
582     if (!SetStringProperty(env, arrayObj, "permissionName", record.permissionName)) {
583         return nullptr;
584     }
585     if (!SetIntProperty(env, arrayObj, "accessCount", record.accessCount)) {
586         return nullptr;
587     }
588     if (!SetIntProperty(env, arrayObj, "rejectCount", record.rejectCount)) {
589         return nullptr;
590     }
591     if (!SetLongProperty(env, arrayObj, "lastAccessTime", record.lastAccessTime)) {
592         return nullptr;
593     }
594     if (!SetLongProperty(env, arrayObj, "lastRejectTime", record.lastRejectTime)) {
595         return nullptr;
596     }
597     if (!SetLongProperty(env, arrayObj, "lastAccessDuration", record.lastAccessDuration)) {
598         return nullptr;
599     }
600     if (!SetRefProperty(env, arrayObj, "accessRecords", ConvertUsedRecordDetails(env, record.accessRecords))) {
601         return nullptr;
602     }
603     if (!SetRefProperty(env, arrayObj, "rejectRecords", ConvertUsedRecordDetails(env, record.rejectRecords))) {
604         return nullptr;
605     }
606     return arrayObj;
607 }
608 
ConvertPermissionRecords(ani_env * env,const std::vector<PermissionUsedRecord> & permRecords)609 static ani_ref ConvertPermissionRecords(ani_env* env, const std::vector<PermissionUsedRecord>& permRecords)
610 {
611     ani_object arrayObj = CreateArrayObject(env, permRecords.size());
612     if (arrayObj == nullptr) {
613         return nullptr;
614     }
615     ani_size index = 0;
616     for (const auto& record: permRecords) {
617         ani_ref aniRecord = ConvertSinglePermissionRecord(env, record);
618         if (aniRecord == nullptr) {
619             break;
620         }
621         ani_status status = env->Object_CallMethodByName_Void(
622             arrayObj, "$_set", "ILstd/core/Object;:V", index, aniRecord);
623         if (status != ANI_OK) {
624             LOGE(PRI_DOMAIN, PRI_TAG,
625                 "Failed to Set permission record, status: %{public}d.", static_cast<int32_t>(status));
626             break;
627         }
628         ++index;
629     }
630     return arrayObj;
631 }
632 
ConvertBundleUsedRecord(ani_env * env,const BundleUsedRecord & record)633 static ani_object ConvertBundleUsedRecord(ani_env* env, const BundleUsedRecord& record)
634 {
635     ani_object aniRecord = CreateClassObject(env, "L@ohos/privacyManager/privacyManager/BundleUsedRecordInner;");
636     if (aniRecord == nullptr) {
637         return nullptr;
638     }
639     if (!SetIntProperty(env, aniRecord, "tokenId", static_cast<int32_t>(record.tokenId))) {
640         return nullptr;
641     }
642     if (!SetBoolProperty(env, aniRecord, "isRemote", record.isRemote)) {
643         return nullptr;
644     }
645 
646     if (!SetStringProperty(env, aniRecord, "deviceId", record.deviceId)) {
647         return nullptr;
648     }
649 
650     if (!SetStringProperty(env, aniRecord, "bundleName", record.bundleName)) {
651         return nullptr;
652     }
653 
654     if (!SetRefProperty(env, aniRecord, "permissionRecords", ConvertPermissionRecords(env, record.permissionRecords))) {
655         return nullptr;
656     }
657     return aniRecord;
658 }
659 
ConvertBundleUsedRecords(ani_env * env,const std::vector<BundleUsedRecord> & bundleRecord)660 static ani_object ConvertBundleUsedRecords(ani_env* env, const std::vector<BundleUsedRecord>& bundleRecord)
661 {
662     ani_object arrayObj = CreateArrayObject(env, bundleRecord.size());
663     if (arrayObj == nullptr) {
664         return nullptr;
665     }
666     ani_size index = 0;
667     for (const auto& record : bundleRecord) {
668         ani_ref aniRecord = ConvertBundleUsedRecord(env, record);
669         if (aniRecord == nullptr) {
670             LOGE(PRI_DOMAIN, PRI_TAG, "AniRecord is null.");
671             continue;
672         }
673         ani_status status = env->Object_CallMethodByName_Void(
674             arrayObj, "$_set", "ILstd/core/Object;:V", index, aniRecord);
675         if (status != ANI_OK) {
676             LOGE(PRI_DOMAIN, PRI_TAG, "Set bundle record fail, status: %{public}d.", static_cast<int32_t>(status));
677             continue;
678         }
679         ++index;
680     }
681     return arrayObj;
682 }
683 
ProcessRecordResult(ani_env * env,const PermissionUsedResult & result)684 static ani_object ProcessRecordResult(ani_env* env, const PermissionUsedResult& result)
685 {
686     ani_object aObject = CreateClassObject(env, "L@ohos/privacyManager/privacyManager/PermissionUsedResponseInner;");
687     if (aObject == nullptr) {
688         return nullptr;
689     }
690     if (!SetLongProperty(env, aObject, "beginTime", result.beginTimeMillis)) {
691         return nullptr;
692     }
693     if (!SetLongProperty(env, aObject, "endTime", result.endTimeMillis)) {
694         return nullptr;
695     }
696 
697     if (!SetRefProperty(env, aObject, "bundleRecords", ConvertBundleUsedRecords(env, result.bundleRecords))) {
698         return nullptr;
699     }
700     return aObject;
701 }
702 
ParseRequest(ani_env * env,const ani_object & aniRequest,PermissionUsedRequest & request)703 static bool ParseRequest(ani_env* env, const ani_object& aniRequest, PermissionUsedRequest& request)
704 {
705     ani_class requestClass;
706     if (ANI_OK != env->FindClass("L@ohos/privacyManager/privacyManager/PermissionUsedRequest;", &requestClass)) {
707         return false;
708     }
709     ani_boolean isRequestObject = false;
710     if (ANI_OK != env->Object_InstanceOf(static_cast<ani_object>(aniRequest), requestClass, &isRequestObject)) {
711         return false;
712     }
713     if (!isRequestObject) {
714         LOGE(PRI_DOMAIN, PRI_TAG, "Object is not request type.");
715         return false;
716     }
717 
718     int32_t value;
719     if (!GetIntProperty(env, aniRequest, "tokenId", value)) {
720         return false;
721     }
722     request.tokenId = static_cast<AccessTokenID>(value);
723 
724     if (!GetBoolProperty(env, aniRequest, "isRemote", request.isRemote)) {
725         return false;
726     }
727 
728     if (!GetStringProperty(env, aniRequest, "deviceId", request.deviceId)) {
729         return false;
730     }
731 
732     if (!GetStringProperty(env, aniRequest, "bundleName", request.bundleName)) {
733         return false;
734     }
735 
736     if (!GetLongProperty(env, aniRequest, "beginTime", request.beginTimeMillis)) {
737         return false;
738     }
739 
740     if (!GetLongProperty(env, aniRequest, "endTime", request.endTimeMillis)) {
741         return false;
742     }
743 
744     if (!GetStringVecProperty(env, aniRequest, "permissionNames", request.permissionList)) {
745         return false;
746     }
747 
748     int32_t flag;
749     if (!GetEnumProperty(env, aniRequest, "flag", flag)) {
750         return false;
751     }
752     request.flag = static_cast<PermissionUsageFlag>(flag);
753     return true;
754 }
755 
GetPermissionUsedRecordExecute(ani_env * env,ani_object aniRequest)756 static ani_object GetPermissionUsedRecordExecute([[maybe_unused]] ani_env* env, ani_object aniRequest)
757 {
758     LOGI(PRI_DOMAIN, PRI_TAG, "GetPermissionUsedRecordExecute Call.");
759     if (env == nullptr || aniRequest == nullptr) {
760         LOGE(PRI_DOMAIN, PRI_TAG, "Env or aniRequest is null.");
761         return nullptr;
762     }
763 
764     PermissionUsedRequest request;
765     if (!ParseRequest(env, aniRequest, request)) {
766         return nullptr;
767     }
768 
769     PermissionUsedResult retResult;
770     int32_t errcode = PrivacyKit::GetPermissionUsedRecords(request, retResult);
771     if (errcode != ANI_OK) {
772         int32_t stsCode = GetStsErrorCode(errcode);
773         BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
774         return nullptr;
775     }
776     return ProcessRecordResult(env, retResult);
777 }
778 
ConvertPermissionUsedTypeInfo(ani_env * env,const PermissionUsedTypeInfo & info)779 static ani_object ConvertPermissionUsedTypeInfo(ani_env *env, const PermissionUsedTypeInfo& info)
780 {
781     ani_object aObject = CreateClassObject(env, "L@ohos/privacyManager/privacyManager/PermissionUsedTypeInfoInner;");
782     if (aObject == nullptr) {
783         return nullptr;
784     }
785     if (!SetIntProperty(env, aObject, "tokenId", info.tokenId)) {
786         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to set tokenId.");
787         return nullptr;
788     }
789     if (!SetStringProperty(env, aObject, "permissionName", info.permissionName)) {
790         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to set PermissionName.");
791         return nullptr;
792     }
793     const char* permUsedTypeDes = "L@ohos/privacyManager/privacyManager/PermissionUsedType;";
794     if (!SetEnumProperty(env, aObject, permUsedTypeDes, "usedType", static_cast<uint32_t>(info.type))) {
795         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to set UsedType.");
796         return nullptr;
797     }
798     return aObject;
799 }
800 
ConvertPermissionUsedTypeInfos(ani_env * env,const std::vector<PermissionUsedTypeInfo> & infos)801 static ani_ref ConvertPermissionUsedTypeInfos(ani_env* env, const std::vector<PermissionUsedTypeInfo>& infos)
802 {
803     ani_object arrayObj = CreateArrayObject(env, infos.size());
804     if (arrayObj == nullptr) {
805         return nullptr;
806     }
807     ani_size index = 0;
808     for (const auto& type : infos) {
809         ani_ref aniType = ConvertPermissionUsedTypeInfo(env, type);
810         if (aniType == nullptr) {
811             LOGE(PRI_DOMAIN, PRI_TAG, "AniType is null.");
812             continue;
813         }
814         ani_status status = env->Object_CallMethodByName_Void(
815             arrayObj, "$_set", "ILstd/core/Object;:V", index, aniType);
816         if (status != ANI_OK) {
817             LOGE(PRI_DOMAIN, PRI_TAG, "Failed to Set type, status: %{public}d.", static_cast<int32_t>(status));
818             continue;
819         }
820         ++index;
821     }
822     return arrayObj;
823 }
824 
GetPermissionUsedTypeInfosExecute(ani_env * env,ani_int aniTokenID,ani_string aniPermission)825 static ani_ref GetPermissionUsedTypeInfosExecute([[maybe_unused]] ani_env* env,
826     ani_int aniTokenID, ani_string aniPermission)
827 {
828     if (env == nullptr) {
829         LOGE(PRI_DOMAIN, PRI_TAG, "Env is null.");
830         return nullptr;
831     }
832     AccessTokenID tokenID = static_cast<AccessTokenID>(aniTokenID);
833     std::string permission = ParseAniString(env, static_cast<ani_string>(aniPermission));
834     std::vector<PermissionUsedTypeInfo> typeInfos;
835     int32_t retCode = PrivacyKit::GetPermissionUsedTypeInfos(tokenID, permission, typeInfos);
836     if (retCode != RET_SUCCESS) {
837         BusinessErrorAni::ThrowError(env, GetStsErrorCode(retCode),
838             GetErrorMessage(GetStsErrorCode(retCode)));
839         return nullptr;
840     }
841     return ConvertPermissionUsedTypeInfos(env, typeInfos);
842 }
843 
SetPermissionUsedRecordToggleStatusExecute(ani_env * env,ani_boolean status)844 static void SetPermissionUsedRecordToggleStatusExecute([[maybe_unused]] ani_env* env, ani_boolean status)
845 {
846     if (env == nullptr) {
847         LOGE(PRI_DOMAIN, PRI_TAG, "Env is null.");
848         return;
849     }
850     int32_t userID = 0;
851     int32_t retCode = PrivacyKit::SetPermissionUsedRecordToggleStatus(userID, status);
852     if (retCode != RET_SUCCESS) {
853         int32_t stsCode = BusinessErrorAni::GetStsErrorCode(retCode);
854         BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode));
855     }
856 }
857 
GetPermissionUsedRecordToggleStatusExecute(ani_env * env)858 static ani_boolean GetPermissionUsedRecordToggleStatusExecute([[maybe_unused]] ani_env* env)
859 {
860     if (env == nullptr) {
861         LOGE(PRI_DOMAIN, PRI_TAG, "Env is null.");
862         return false;
863     }
864     int32_t userID = 0;
865     bool isToggleStatus = false;
866     int32_t retCode = PrivacyKit::GetPermissionUsedRecordToggleStatus(userID, isToggleStatus);
867     if (retCode != RET_SUCCESS) {
868         BusinessErrorAni::ThrowError(env, GetStsErrorCode(retCode), GetErrorMessage(GetStsErrorCode(retCode)));
869         return false;
870     }
871     return isToggleStatus;
872 }
873 
InitPrivacyFunction(ani_env * env)874 void InitPrivacyFunction(ani_env *env)
875 {
876     LOGI(PRI_DOMAIN, PRI_TAG, "InitPrivacyFunction call.");
877     if (env == nullptr) {
878         LOGE(PRI_DOMAIN, PRI_TAG, "Env is null.");
879         return;
880     }
881     if (env->ResetError() != ANI_OK) {
882         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to ResetError.");
883     }
884 
885     ani_namespace ns;
886     if (ANI_OK != env->FindNamespace("L@ohos/privacyManager/privacyManager;", &ns)) {
887         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to FindNamespace privacyManager.");
888         return;
889     }
890 
891     // namespace method input param without ani_object
892     std::array nsMethods = {
893         ani_native_function {"addPermissionUsedRecordExecute", nullptr,
894             reinterpret_cast<void *>(AddPermissionUsedRecordExecute)},
895         ani_native_function {"startUsingPermissionExecute", nullptr,
896             reinterpret_cast<void *>(StartUsingPermissionExecute)},
897         ani_native_function {"stopUsingPermissionExecute", nullptr,
898             reinterpret_cast<void *>(StopUsingPermissionExecute)},
899         ani_native_function {"getPermissionUsedRecordExecute", nullptr,
900             reinterpret_cast<void *>(GetPermissionUsedRecordExecute)},
901         ani_native_function {"getPermissionUsedTypeInfosExecute", nullptr,
902             reinterpret_cast<void *>(GetPermissionUsedTypeInfosExecute)},
903         ani_native_function {"setPermissionUsedRecordToggleStatusExecute",
904             nullptr, reinterpret_cast<void *>(SetPermissionUsedRecordToggleStatusExecute)},
905         ani_native_function {"getPermissionUsedRecordToggleStatusExecute",
906             nullptr, reinterpret_cast<void *>(GetPermissionUsedRecordToggleStatusExecute)},
907         ani_native_function {"onExecute", nullptr, reinterpret_cast<void *>(RegisterPermActiveStatusCallback)},
908         ani_native_function {"offExecute", nullptr, reinterpret_cast<void *>(UnRegisterPermActiveStatusCallback)},
909     };
910     ani_status status = env->Namespace_BindNativeFunctions(ns, nsMethods.data(), nsMethods.size());
911     if (status != ANI_OK) {
912         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to Namespace_BindNativeFunctions status : %{public}d.", status);
913     }
914     if (env->ResetError() != ANI_OK) {
915         LOGE(PRI_DOMAIN, PRI_TAG, "Failed to ResetError.");
916     }
917     LOGI(PRI_DOMAIN, PRI_TAG, "InitPrivacyFunction end.");
918 }
919 
920 extern "C" {
ANI_Constructor(ani_vm * vm,uint32_t * result)921 ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
922 {
923     LOGI(PRI_DOMAIN, PRI_TAG, "ANI_Constructor begin.");
924     if (vm == nullptr || result == nullptr) {
925         LOGE(PRI_DOMAIN, PRI_TAG, "Vm or result is null.");
926         return ANI_INVALID_ARGS;
927     }
928     ani_env* env;
929     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
930         LOGE(PRI_DOMAIN, PRI_TAG, "Unsupported ANI_VERSION_1.");
931         return ANI_OUT_OF_MEMORY;
932     }
933     InitPrivacyFunction(env);
934     *result = ANI_VERSION_1;
935     LOGI(PRI_DOMAIN, PRI_TAG, "ANI_Constructor end.");
936     return ANI_OK;
937 }
938 }
939 } // namespace AccessToken
940 } // namespace Security
941 } // namespace OHOS