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, "get object failed");
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, "null method %{public}s", methodName.data());
52 return;
53 }
54
55 napi_value argv[] = { CreateJsConfiguration(env_, config) };
56 napi_call_function(env_, obj, method, ArraySize(argv), argv, nullptr);
57 }
58 }
59
OnConfigurationUpdated(const AppExecFwk::Configuration & config)60 void JsEnvironmentCallback::OnConfigurationUpdated(const AppExecFwk::Configuration &config)
61 {
62 std::weak_ptr<JsEnvironmentCallback> thisWeakPtr(shared_from_this());
63 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
64 [thisWeakPtr, config, callbacks = callbacks_, callbacksSync = callbacksSync_]
65 (napi_env env, NapiAsyncTask &task, int32_t status) {
66 std::shared_ptr<JsEnvironmentCallback> jsEnvCallback = thisWeakPtr.lock();
67 if (jsEnvCallback) {
68 jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacks);
69 jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacksSync);
70 }
71 }
72 );
73 napi_ref callback = nullptr;
74 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
75 NapiAsyncTask::ScheduleLowQos("JsEnvironmentCallback::OnConfigurationUpdated",
76 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
77 }
78
CallMemoryLevelInner(const std::string & methodName,const int level,const std::map<int32_t,std::shared_ptr<NativeReference>> & callbacks)79 void JsEnvironmentCallback::CallMemoryLevelInner(const std::string &methodName, const int level,
80 const std::map<int32_t, std::shared_ptr<NativeReference>> &callbacks)
81 {
82 TAG_LOGD(AAFwkTag::APPKIT, "methodName = %{public}s", methodName.c_str());
83 for (auto &callback : callbacks) {
84 if (!callback.second) {
85 TAG_LOGE(AAFwkTag::APPKIT, "Invalid jsCallback");
86 return;
87 }
88
89 auto obj = callback.second->GetNapiValue();
90 if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
91 TAG_LOGE(AAFwkTag::APPKIT, "get object failed");
92 return;
93 }
94
95 napi_value method = nullptr;
96 napi_get_named_property(env_, obj, methodName.data(), &method);
97 if (method == nullptr) {
98 TAG_LOGE(AAFwkTag::APPKIT, "null method %{public}s", methodName.data());
99 return;
100 }
101
102 napi_value argv[] = { CreateJsValue(env_, level) };
103 napi_call_function(env_, obj, method, ArraySize(argv), argv, nullptr);
104 }
105 }
106
OnMemoryLevel(const int level)107 void JsEnvironmentCallback::OnMemoryLevel(const int level)
108 {
109 std::weak_ptr<JsEnvironmentCallback> thisWeakPtr(shared_from_this());
110 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
111 [thisWeakPtr, level, callbacks = callbacks_, callbacksSync = callbacksSync_]
112 (napi_env env, NapiAsyncTask &task, int32_t status) {
113 std::shared_ptr<JsEnvironmentCallback> jsEnvCallback = thisWeakPtr.lock();
114 if (jsEnvCallback) {
115 jsEnvCallback->CallMemoryLevelInner("onMemoryLevel", level, callbacks);
116 jsEnvCallback->CallMemoryLevelInner("onMemoryLevel", level, callbacksSync);
117 }
118 }
119 );
120 napi_ref callback = nullptr;
121 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
122 NapiAsyncTask::Schedule("JsEnvironmentCallback::OnMemoryLevel",
123 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
124 }
125
Register(napi_value jsCallback,bool isSync)126 int32_t JsEnvironmentCallback::Register(napi_value jsCallback, bool isSync)
127 {
128 if (env_ == nullptr) {
129 return -1;
130 }
131 int32_t callbackId = serialNumber_;
132 if (serialNumber_ < INT32_MAX) {
133 serialNumber_++;
134 } else {
135 serialNumber_ = 0;
136 }
137 napi_ref ref = nullptr;
138 napi_create_reference(env_, jsCallback, 1, &ref);
139 if (isSync) {
140 callbacksSync_.emplace(callbackId, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
141 } else {
142 callbacks_.emplace(callbackId, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
143 }
144 return callbackId;
145 }
146
UnRegister(int32_t callbackId,bool isSync)147 bool JsEnvironmentCallback::UnRegister(int32_t callbackId, bool isSync)
148 {
149 TAG_LOGD(AAFwkTag::APPKIT, "callbackId : %{public}d", callbackId);
150 if (isSync) {
151 auto it = callbacksSync_.find(callbackId);
152 if (it == callbacksSync_.end()) {
153 TAG_LOGE(AAFwkTag::APPKIT, "callbackId: %{public}d not in callbacksSync_", callbackId);
154 return false;
155 }
156 TAG_LOGD(AAFwkTag::APPKIT, "callbacksSync_.callbackId : %{public}d", it->first);
157 return callbacksSync_.erase(callbackId) == 1;
158 }
159 auto it = callbacks_.find(callbackId);
160 if (it == callbacks_.end()) {
161 TAG_LOGE(AAFwkTag::APPKIT, "callbackId: %{public}d not in callbacks_", callbackId);
162 return false;
163 }
164 TAG_LOGD(AAFwkTag::APPKIT, "callbacks_.callbackId : %{public}d", it->first);
165 return callbacks_.erase(callbackId) == 1;
166 }
167
IsEmpty() const168 bool JsEnvironmentCallback::IsEmpty() const
169 {
170 return callbacks_.empty() && callbacksSync_.empty();
171 }
172 } // namespace AbilityRuntime
173 } // namespace OHOS
174