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