1 /*
2 * Copyright (c) 2025-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 "napi_ref_manager.h"
17
18 #include "camera_log.h"
19 #include "napi/native_api.h"
20
21 namespace OHOS {
22 namespace CameraStandard {
23 /**
24 * Create a memory-safe reference
25 * @param env The napi environment
26 * @param value The napi value
27 * @param result Output parameter, returns the created reference
28 * @return napi status code, napi_ok indicates success
29 */
CreateMemSafetyRef(napi_env env,napi_value value,napi_ref * result)30 napi_status NapiRefManager::CreateMemSafetyRef(napi_env env, napi_value value, napi_ref* result)
31 {
32 MEDIA_DEBUG_LOG("NapiRefManager::CreateMemSafetyRef enter");
33 CHECK_RETURN_RET_ELOG(
34 !result || !env, napi_status::napi_invalid_arg, "NapiRefManager::CreateMemSafetyRef env or result is nullptr ");
35 napi_status status = napi_create_reference(env, value, 1, result);
36 CHECK_RETURN_RET_ELOG(status != napi_ok, status, "NapiRefManager::CreateMemSafetyRef create ref fail");
37 std::lock_guard<std::mutex> lock(mutex_);
38 auto& pr = envToRefMap_[env];
39 auto& [mpEnv, mpRefSet] = pr;
40 mpEnv = env;
41 mpRefSet.insert(*result);
42 MEDIA_DEBUG_LOG("NapiRefManager::CreateMemSafetyRef map.size: %{public}d, set.size: %{public}d",
43 static_cast<int32_t>(envToRefMap_.size()), static_cast<int32_t>(mpRefSet.size()));
44 // Add an environment cleanup hook
45 if (mpRefSet.size() == 1) {
46 status = napi_add_env_cleanup_hook(env, NapiRefManager::CleanUpHook, &pr);
47 CHECK_PRINT_WLOG(status != napi_ok,
48 "NapiRefManager::CreateMemSafetyRef napi_add_env_cleanup_hook status: %{public}d",
49 static_cast<int32_t>(status));
50 }
51 return status;
52 }
53
54 /**
55 * Cleanup hook function
56 * @param pPr Pointer to the pair of env and refSet
57 */
CleanUpHook(void * pPr)58 void NapiRefManager::CleanUpHook(void* pPr)
59 {
60 MEDIA_INFO_LOG("NapiRefManager::CleanUpHook CleanUpHook enter");
61 CHECK_RETURN(!pPr);
62 auto& [mpEnv, _] = *reinterpret_cast<std::pair<napi_env, std::unordered_set<napi_ref>>*>(pPr);
63 NapiRefManager::CleanUpHookImpl(mpEnv);
64 }
65
66 /**
67 * Cleanup hook implementation function
68 * @param env The napi environment
69 */
CleanUpHookImpl(napi_env env)70 void NapiRefManager::CleanUpHookImpl(napi_env env)
71 {
72 MEDIA_INFO_LOG("NapiRefManager::CleanUpHookImpl enter");
73 CHECK_RETURN(!env);
74 std::lock_guard<std::mutex> lock(mutex_);
75 auto& [_, refSet] = envToRefMap_[env];
76 MEDIA_INFO_LOG("NapiRefManager::CleanUpHookImpl to del ref, size: %{public}d", static_cast<int32_t>(refSet.size()));
77 // Iterate through the set and delete all references
78 for (auto& ref : refSet) {
79 napi_status status = napi_delete_reference(env, ref);
80 CHECK_PRINT_WLOG(
81 status != napi_ok, "NapiRefManager::CleanUpHookImpl status: %{public}d", static_cast<int32_t>(status));
82 }
83 // Remove the environment entry from the map
84 envToRefMap_.erase(env);
85 }
86
87 std::mutex NapiRefManager::mutex_;
88 std::unordered_map<napi_env, std::pair<napi_env, std::unordered_set<napi_ref>>> NapiRefManager::envToRefMap_;
89 } // namespace CameraStandard
90 } // namespace OHOS
91