• 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 
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, &parameterCount, 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, &parameterCount, 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