1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "environment_callback.h"
17
18 #include "hilog_tag_wrapper.h"
19 #include "hitrace_meter.h"
20 #include "js_data_struct_converter.h"
21 #include "js_runtime_utils.h"
22
23 namespace OHOS {
24 namespace AbilityRuntime {
JsEnvironmentCallback(napi_env env)25 JsEnvironmentCallback::JsEnvironmentCallback(napi_env env)
26 : env_(env)
27 {
28 }
29
30 int32_t JsEnvironmentCallback::serialNumber_ = 0;
31
CallConfigurationUpdatedInner(const std::string & methodName,const AppExecFwk::Configuration & config,const std::map<int32_t,std::shared_ptr<NativeReference>> & callbacks)32 void JsEnvironmentCallback::CallConfigurationUpdatedInner(const std::string &methodName,
33 const AppExecFwk::Configuration &config, const std::map<int32_t, std::shared_ptr<NativeReference>> &callbacks)
34 {
35 TAG_LOGD(AAFwkTag::APPKIT, "methodName = %{public}s", methodName.c_str());
36 for (auto &callback : callbacks) {
37 if (!callback.second) {
38 TAG_LOGE(AAFwkTag::APPKIT, " Invalid jsCallback");
39 return;
40 }
41
42 auto obj = callback.second->GetNapiValue();
43 if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
44 TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
45 return;
46 }
47
48 napi_value method = nullptr;
49 napi_get_named_property(env_, obj, methodName.data(), &method);
50 if (method == nullptr) {
51 TAG_LOGE(AAFwkTag::APPKIT, "Failed to get %{public}s from object",
52 methodName.data());
53 return;
54 }
55
56 napi_value argv[] = { CreateJsConfiguration(env_, config) };
57 napi_call_function(env_, obj, method, ArraySize(argv), argv, nullptr);
58 }
59 }
60
OnConfigurationUpdated(const AppExecFwk::Configuration & config)61 void JsEnvironmentCallback::OnConfigurationUpdated(const AppExecFwk::Configuration &config)
62 {
63 std::weak_ptr<JsEnvironmentCallback> thisWeakPtr(shared_from_this());
64 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
65 [thisWeakPtr, config, callbacks = callbacks_, callbacksSync = callbacksSync_]
66 (napi_env env, NapiAsyncTask &task, int32_t status) {
67 std::shared_ptr<JsEnvironmentCallback> jsEnvCallback = thisWeakPtr.lock();
68 if (jsEnvCallback) {
69 jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacks);
70 jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacksSync);
71 }
72 }
73 );
74 napi_ref callback = nullptr;
75 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
76 NapiAsyncTask::Schedule("JsEnvironmentCallback::OnConfigurationUpdated",
77 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
78 }
79
CallMemoryLevelInner(const std::string & methodName,const int level,const std::map<int32_t,std::shared_ptr<NativeReference>> & callbacks)80 void JsEnvironmentCallback::CallMemoryLevelInner(const std::string &methodName, const int level,
81 const std::map<int32_t, std::shared_ptr<NativeReference>> &callbacks)
82 {
83 TAG_LOGD(AAFwkTag::APPKIT, "methodName = %{public}s", methodName.c_str());
84 for (auto &callback : callbacks) {
85 if (!callback.second) {
86 TAG_LOGE(AAFwkTag::APPKIT, "Invalid jsCallback");
87 return;
88 }
89
90 auto obj = callback.second->GetNapiValue();
91 if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
92 TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
93 return;
94 }
95
96 napi_value method = nullptr;
97 napi_get_named_property(env_, obj, methodName.data(), &method);
98 if (method == nullptr) {
99 TAG_LOGE(AAFwkTag::APPKIT, "Failed to get %{public}s from object", methodName.data());
100 return;
101 }
102
103 napi_value argv[] = { CreateJsValue(env_, level) };
104 napi_call_function(env_, obj, method, ArraySize(argv), argv, nullptr);
105 }
106 }
107
OnMemoryLevel(const int level)108 void JsEnvironmentCallback::OnMemoryLevel(const int level)
109 {
110 std::weak_ptr<JsEnvironmentCallback> thisWeakPtr(shared_from_this());
111 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
112 [thisWeakPtr, level, callbacks = callbacks_, callbacksSync = callbacksSync_]
113 (napi_env env, NapiAsyncTask &task, int32_t status) {
114 std::shared_ptr<JsEnvironmentCallback> jsEnvCallback = thisWeakPtr.lock();
115 if (jsEnvCallback) {
116 jsEnvCallback->CallMemoryLevelInner("onMemoryLevel", level, callbacks);
117 jsEnvCallback->CallMemoryLevelInner("onMemoryLevel", level, callbacksSync);
118 }
119 }
120 );
121 napi_ref callback = nullptr;
122 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
123 NapiAsyncTask::Schedule("JsEnvironmentCallback::OnMemoryLevel",
124 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
125 }
126
Register(napi_value jsCallback,bool isSync)127 int32_t JsEnvironmentCallback::Register(napi_value jsCallback, bool isSync)
128 {
129 if (env_ == nullptr) {
130 return -1;
131 }
132 int32_t callbackId = serialNumber_;
133 if (serialNumber_ < INT32_MAX) {
134 serialNumber_++;
135 } else {
136 serialNumber_ = 0;
137 }
138 napi_ref ref = nullptr;
139 napi_create_reference(env_, jsCallback, 1, &ref);
140 if (isSync) {
141 callbacksSync_.emplace(callbackId, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
142 } else {
143 callbacks_.emplace(callbackId, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
144 }
145 return callbackId;
146 }
147
UnRegister(int32_t callbackId,bool isSync)148 bool JsEnvironmentCallback::UnRegister(int32_t callbackId, bool isSync)
149 {
150 TAG_LOGD(AAFwkTag::APPKIT, "callbackId : %{public}d", callbackId);
151 if (isSync) {
152 auto it = callbacksSync_.find(callbackId);
153 if (it == callbacksSync_.end()) {
154 TAG_LOGE(AAFwkTag::APPKIT, "callbackId: %{public}d is not in callbacksSync_", callbackId);
155 return false;
156 }
157 TAG_LOGD(AAFwkTag::APPKIT, "callbacksSync_.callbackId : %{public}d", it->first);
158 return callbacksSync_.erase(callbackId) == 1;
159 }
160 auto it = callbacks_.find(callbackId);
161 if (it == callbacks_.end()) {
162 TAG_LOGE(AAFwkTag::APPKIT, "callbackId: %{public}d is not in callbacks_", callbackId);
163 return false;
164 }
165 TAG_LOGD(AAFwkTag::APPKIT, "callbacks_.callbackId : %{public}d", it->first);
166 return callbacks_.erase(callbackId) == 1;
167 }
168
IsEmpty() const169 bool JsEnvironmentCallback::IsEmpty() const
170 {
171 return callbacks_.empty() && callbacksSync_.empty();
172 }
173 } // namespace AbilityRuntime
174 } // namespace OHOS