1 /*
2 * Copyright (C) 2021 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_state_registry.h"
17
18 #include <map>
19 #include <utility>
20
21 #include "event_listener_manager.h"
22 #include "napi_parameter_util.h"
23 #include "napi_telephony_observer.h"
24 #include "napi_util.h"
25 #include "state_registry_errors.h"
26 #include "telephony_errors.h"
27 #include "telephony_log_wrapper.h"
28 #include "telephony_state_manager.h"
29
30 namespace OHOS {
31 namespace Telephony {
32 namespace {
33 constexpr const char *OBSERVER_JS_PERMISSION_ERROR_STRING =
34 "Permission denied. An attempt was made to Observer "
35 "On forbidden by permission : ohos.permission.GET_NETWORK_INFO or ohos.permission.LOCATION ";
36 constexpr int32_t ARRAY_SIZE = 64;
37
38 const std::map<std::string_view, TelephonyUpdateEventType> eventMap {
39 {"networkStateChange", TelephonyUpdateEventType::EVENT_NETWORK_STATE_UPDATE},
40 {"callStateChange", TelephonyUpdateEventType::EVENT_CALL_STATE_UPDATE},
41 {"signalInfoChange", TelephonyUpdateEventType::EVENT_SIGNAL_STRENGTHS_UPDATE},
42 {"simStateChange", TelephonyUpdateEventType::EVENT_SIM_STATE_UPDATE},
43 {"cellInfoChange", TelephonyUpdateEventType::EVENT_CELL_INFO_UPDATE},
44 {"cellularDataConnectionStateChange", TelephonyUpdateEventType::EVENT_DATA_CONNECTION_UPDATE},
45 {"cellularDataFlowChange", TelephonyUpdateEventType::EVENT_CELLULAR_DATA_FLOW_UPDATE},
46 };
47
GetEventType(std::string_view event)48 TelephonyUpdateEventType GetEventType(std::string_view event)
49 {
50 auto serched = eventMap.find(event);
51 return (serched != eventMap.end() ? serched->second : TelephonyUpdateEventType::NONE_EVENT_TYPE);
52 }
53 } // namespace
54
IsValidSlotId(int32_t slotId)55 static inline bool IsValidSlotId(int32_t slotId)
56 {
57 return ((slotId >= DEFAULT_SIM_SLOT_ID) && (slotId < SIM_SLOT_COUNT));
58 }
59
NativeOn(napi_env env,void * data)60 static void NativeOn(napi_env env, void *data)
61 {
62 if (data == nullptr) {
63 TELEPHONY_LOGE("NativeOn data is nullptr");
64 NapiUtil::ThrowParameterError(env);
65 return;
66 }
67 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
68 if (!IsValidSlotId(asyncContext->slotId)) {
69 TELEPHONY_LOGE("NativeOn slotId is invalid");
70 asyncContext->errorCode = ERROR_SLOT_ID_INVALID;
71 return;
72 }
73 TELEPHONY_LOGI("NativeOn eventType = %{public}d", asyncContext->eventType);
74 std::shared_ptr<bool> isDeleting = std::make_shared<bool>(false);
75 EventListener listener {
76 env,
77 asyncContext->eventType,
78 asyncContext->slotId,
79 asyncContext->callbackRef,
80 isDeleting,
81 };
82 asyncContext->errorCode = EventListenerManager::RegisterEventListener(listener);
83 if (asyncContext->errorCode == TELEPHONY_SUCCESS) {
84 asyncContext->resolved = true;
85 }
86 }
87
OnCallback(napi_env env,void * data)88 static void OnCallback(napi_env env, void *data)
89 {
90 if (data == nullptr) {
91 TELEPHONY_LOGE("OnCallback data is nullptr");
92 NapiUtil::ThrowParameterError(env);
93 return;
94 }
95 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
96 if (!asyncContext->resolved) {
97 TELEPHONY_LOGE("OnCallback error by add observer failed");
98 if (asyncContext->errorCode == TELEPHONY_STATE_REGISTRY_PERMISSION_DENIED) {
99 NapiUtil::ThrowError(env, JS_ERROR_TELEPHONY_PERMISSION_DENIED, OBSERVER_JS_PERMISSION_ERROR_STRING);
100 } else {
101 JsError error = NapiUtil::ConverErrorMessageForJs(asyncContext->errorCode);
102 NapiUtil::ThrowError(env, error.errorCode, error.errorMessage);
103 }
104 }
105 delete asyncContext;
106 }
107
On(napi_env env,napi_callback_info info)108 static napi_value On(napi_env env, napi_callback_info info)
109 {
110 size_t parameterCount = 3;
111 napi_value parameters[] = { nullptr, nullptr, nullptr };
112 napi_get_cb_info(env, info, ¶meterCount, parameters, nullptr, nullptr);
113
114 std::unique_ptr<ObserverContext> asyncContext = std::make_unique<ObserverContext>();
115 if (asyncContext == nullptr) {
116 TELEPHONY_LOGE("On asyncContext is nullptr.");
117 NapiUtil::ThrowParameterError(env);
118 return nullptr;
119 }
120 std::array<char, ARRAY_SIZE> eventType {};
121 napi_value object = NapiUtil::CreateUndefined(env);
122 std::optional<NapiError> errCode;
123 if (parameterCount == std::size(parameters)) {
124 auto paraTuple = std::make_tuple(std::data(eventType), &object, &asyncContext->callbackRef);
125 errCode = MatchParameters(env, parameters, parameterCount, paraTuple);
126 if (!errCode.has_value()) {
127 napi_value slotId = NapiUtil::GetNamedProperty(env, object, "slotId");
128 if (slotId) {
129 NapiValueToCppValue(env, slotId, napi_number, &asyncContext->slotId);
130 TELEPHONY_LOGI("state registry on slotId = %{public}d", asyncContext->slotId);
131 }
132 }
133 } else {
134 auto paraTuple = std::make_tuple(std::data(eventType), &asyncContext->callbackRef);
135 errCode = MatchParameters(env, parameters, parameterCount, paraTuple);
136 }
137
138 if (errCode.has_value()) {
139 TELEPHONY_LOGE("On parameter matching failed.");
140 NapiUtil::ThrowParameterError(env);
141 return nullptr;
142 }
143
144 asyncContext->eventType = GetEventType(eventType.data());
145 if (asyncContext->eventType != TelephonyUpdateEventType::NONE_EVENT_TYPE) {
146 ObserverContext *observerContext = asyncContext.release();
147 NativeOn(env, observerContext);
148 OnCallback(env, observerContext);
149 } else {
150 NapiUtil::ThrowParameterError(env);
151 }
152 return NapiUtil::CreateUndefined(env);
153 }
154
NativeOff(napi_env env,void * data)155 static void NativeOff(napi_env env, void *data)
156 {
157 if (data == nullptr) {
158 TELEPHONY_LOGE("NativeOff data is nullptr");
159 NapiUtil::ThrowParameterError(env);
160 return;
161 }
162
163 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
164 if (asyncContext->callbackRef == nullptr) {
165 asyncContext->errorCode = EventListenerManager::UnregisterEventListener(
166 env, asyncContext->eventType, asyncContext->removeListenerList);
167 } else {
168 asyncContext->errorCode = EventListenerManager::UnregisterEventListener(
169 env, asyncContext->eventType, asyncContext->callbackRef, asyncContext->removeListenerList);
170 }
171
172 if (asyncContext->errorCode == TELEPHONY_SUCCESS) {
173 asyncContext->resolved = true;
174 }
175 }
176
OffCallback(napi_env env,void * data)177 static void OffCallback(napi_env env, void *data)
178 {
179 if (data == nullptr) {
180 TELEPHONY_LOGE("OffCallback data is nullptr");
181 NapiUtil::ThrowParameterError(env);
182 return;
183 }
184 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
185 for (auto listener : asyncContext->removeListenerList) {
186 if (env == listener.env && listener.env != nullptr && listener.callbackRef != nullptr) {
187 napi_delete_reference(listener.env, listener.callbackRef);
188 }
189 }
190 asyncContext->removeListenerList.clear();
191 if (!asyncContext->resolved) {
192 TELEPHONY_LOGE("OffCallback error by remove observer failed");
193 if (asyncContext->errorCode == TELEPHONY_STATE_REGISTRY_PERMISSION_DENIED) {
194 NapiUtil::ThrowError(env, JS_ERROR_TELEPHONY_PERMISSION_DENIED, OBSERVER_JS_PERMISSION_ERROR_STRING);
195 } else {
196 JsError error = NapiUtil::ConverErrorMessageForJs(asyncContext->errorCode);
197 NapiUtil::ThrowError(env, error.errorCode, error.errorMessage);
198 }
199 }
200 if (env != nullptr && asyncContext->callbackRef != nullptr) {
201 napi_delete_reference(env, asyncContext->callbackRef);
202 asyncContext->callbackRef = nullptr;
203 }
204 delete asyncContext;
205 }
206
Off(napi_env env,napi_callback_info info)207 static napi_value Off(napi_env env, napi_callback_info info)
208 {
209 size_t parameterCount = 2;
210 napi_value parameters[] = { nullptr, nullptr };
211 napi_get_cb_info(env, info, ¶meterCount, parameters, nullptr, nullptr);
212
213 std::array<char, ARRAY_SIZE> eventType {};
214 std::unique_ptr<ObserverContext> asyncContext = std::make_unique<ObserverContext>();
215 if (asyncContext == nullptr) {
216 TELEPHONY_LOGE("Off asyncContext is nullptr.");
217 NapiUtil::ThrowParameterError(env);
218 return nullptr;
219 }
220 auto paraTuple = std::make_tuple(std::data(eventType), &asyncContext->callbackRef);
221 std::optional<NapiError> errCode = MatchParameters(env, parameters, parameterCount, paraTuple);
222 if (errCode.has_value()) {
223 TELEPHONY_LOGE("Off parameter matching failed.");
224 NapiUtil::ThrowParameterError(env);
225 return nullptr;
226 }
227
228 asyncContext->eventType = GetEventType(eventType.data());
229 if (asyncContext->eventType != TelephonyUpdateEventType::NONE_EVENT_TYPE) {
230 ObserverContext *observerContext = asyncContext.release();
231 NativeOff(env, observerContext);
232 OffCallback(env, observerContext);
233 } else {
234 NapiUtil::ThrowParameterError(env);
235 }
236 return NapiUtil::CreateUndefined(env);
237 }
238
InitEnumLockReason(napi_env env,napi_value exports)239 napi_status InitEnumLockReason(napi_env env, napi_value exports)
240 {
241 napi_property_descriptor desc[] = {
242 DECLARE_NAPI_STATIC_PROPERTY("SIM_NONE", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_NONE))),
243 DECLARE_NAPI_STATIC_PROPERTY("SIM_PIN", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PIN))),
244 DECLARE_NAPI_STATIC_PROPERTY("SIM_PUK", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PUK))),
245 DECLARE_NAPI_STATIC_PROPERTY("SIM_PN_PIN", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PN_PIN))),
246 DECLARE_NAPI_STATIC_PROPERTY("SIM_PN_PUK", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PN_PUK))),
247 DECLARE_NAPI_STATIC_PROPERTY("SIM_PU_PIN", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PU_PIN))),
248 DECLARE_NAPI_STATIC_PROPERTY("SIM_PU_PUK", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PU_PUK))),
249 DECLARE_NAPI_STATIC_PROPERTY("SIM_PP_PIN", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PP_PIN))),
250 DECLARE_NAPI_STATIC_PROPERTY("SIM_PP_PUK", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PP_PUK))),
251 DECLARE_NAPI_STATIC_PROPERTY("SIM_PC_PIN", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PC_PIN))),
252 DECLARE_NAPI_STATIC_PROPERTY("SIM_PC_PUK", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_PC_PUK))),
253 DECLARE_NAPI_STATIC_PROPERTY("SIM_SIM_PIN", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_SIM_PIN))),
254 DECLARE_NAPI_STATIC_PROPERTY("SIM_SIM_PUK", GetNapiValue(env, static_cast<int32_t>(LockReason::SIM_SIM_PUK))),
255 };
256
257 constexpr size_t arrSize = sizeof(desc) / sizeof(desc[0]);
258 NapiUtil::DefineEnumClassByName(env, exports, "LockReason", arrSize, desc);
259 return napi_define_properties(env, exports, arrSize, desc);
260 }
261
262 EXTERN_C_START
InitNapiStateRegistry(napi_env env,napi_value exports)263 napi_value InitNapiStateRegistry(napi_env env, napi_value exports)
264 {
265 napi_property_descriptor desc[] = {
266 DECLARE_NAPI_FUNCTION("on", On),
267 DECLARE_NAPI_FUNCTION("off", Off),
268 };
269 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
270 NAPI_CALL(env, InitEnumLockReason(env, exports));
271 const char *nativeStr = "InitNapiStateRegistry";
272 napi_wrap(
273 env, exports, static_cast<void *>(const_cast<char *>(nativeStr)),
274 [](napi_env env, void *data, void *hint) { EventListenerManager::UnRegisterAllListener(env); }, nullptr,
275 nullptr);
276 return exports;
277 }
278 EXTERN_C_END
279
280 static napi_module _stateRegistryModule = {
281 .nm_version = 1,
282 .nm_flags = 0,
283 .nm_filename = nullptr,
284 .nm_register_func = InitNapiStateRegistry,
285 .nm_modname = "telephony.observer",
286 .nm_priv = nullptr,
287 .reserved = { nullptr },
288 };
289
RegisterTelephonyObserverModule(void)290 extern "C" __attribute__((constructor)) void RegisterTelephonyObserverModule(void)
291 {
292 napi_module_register(&_stateRegistryModule);
293 }
294 } // namespace Telephony
295 } // namespace OHOS
296