1 /*
2  * Copyright (c) 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 #ifdef FEATURE_GNSS_SUPPORT
17 #include "agnss_ni_manager.h"
18 
19 #include "call_manager_client.h"
20 #include "gnss_ability.h"
21 #include "idevmgr_hdi.h"
22 #include "iservice_registry.h"
23 #include "location_data_rdb_manager.h"
24 #include "location_log.h"
25 #include "nlohmann/json.hpp"
26 #ifdef NOTIFICATION_ENABLE
27 #include "notification_helper.h"
28 #endif
29 #include "securec.h"
30 #include "sms_service_manager_client.h"
31 #include "string_utils.h"
32 #include "system_ability_definition.h"
33 #include "ui_extension_ability_connection.h"
34 #include "want_agent_helper.h"
35 #include "want_agent_info.h"
36 
37 namespace OHOS {
38 namespace Location {
39 using namespace EventFwk;
40 constexpr uint32_t MAX_RETRY_TIMES = 3;
41 constexpr uint32_t TIME_AFTER_EMERGENCY_CALL = 10 * 1000;
42 constexpr int32_t INVALID_SUBID = -1;
43 const std::string URN_APPLICATION_ID = "x-oma-application:ulp.ua";
44 const std::string AGNSS_NI_SERVICE_NAME = "agnss_ni";
45 const std::string LOCATION_DIALOG_BUNDLE_NAME = "com.ohos.locationdialog";
46 const std::string AGNSS_NI_DIALOG_ABILITY_NAME = "ConfirmUIExtAbility";
47 #ifdef NOTIFICATION_ENABLE
48 const int32_t GNSS_AGNSS_NI_NOTIFICATION_ID = LOCATION_GNSS_SA_ID * 100;
49 constexpr uint32_t NOTIFICATION_AUTO_DELETED_TIME = 1000;
50 #endif
51 
GetInstance()52 AGnssNiManager* AGnssNiManager::GetInstance()
53 {
54     static AGnssNiManager data;
55     return &data;
56 }
57 
AGnssNiManager()58 AGnssNiManager::AGnssNiManager()
59 {}
60 
~AGnssNiManager()61 AGnssNiManager::~AGnssNiManager()
62 {}
63 
SubscribeSaStatusChangeListerner()64 void AGnssNiManager::SubscribeSaStatusChangeListerner()
65 {
66     LBSLOGI(GNSS, "AGNSS-NI SubscribeSaStatusChangeListerner");
67     sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
68     if (samgrProxy == nullptr) {
69         LBSLOGE(GNSS, "failed to get samgrProxy");
70         return;
71     }
72     statusChangeListener_ = new SystemAbilityStatusChangeListener();
73     if (statusChangeListener_ == nullptr) {
74         LBSLOGE(GNSS, "statusChangeListener_ is nullptr!");
75         return;
76     }
77     int32_t ret = samgrProxy->SubscribeSystemAbility(COMMON_EVENT_SERVICE_ID, statusChangeListener_);
78     if (ret != ERR_OK) {
79         LBSLOGE(GNSS, "subscribe systemAbilityId: call manager service failed!");
80         return;
81     }
82 }
83 
RegisterAgnssNiEvent()84 void AGnssNiManager::RegisterAgnssNiEvent()
85 {
86     MatchingSkills matchingSkills;
87     matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_SMS_WAPPUSH_RECEIVE_COMPLETED);
88     matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_SMS_RECEIVE_COMPLETED);
89     matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_CALL_STATE_CHANGED);
90     CommonEventSubscribeInfo subscriberInfo(matchingSkills);
91     subscriber_ = std::make_shared<GnssCommonEventSubscriber>(subscriberInfo);
92 
93     uint32_t count = 0;
94     bool result = false;
95     while (!result && count <= MAX_RETRY_TIMES) {
96         result = CommonEventManager::SubscribeCommonEvent(subscriber_);
97         count++;
98     }
99     if (count > MAX_RETRY_TIMES || !result) {
100         LBSLOGE(GNSS, "Failed to subscriber gnss event");
101     } else {
102         LBSLOGI(GNSS, "success to subscriber gnss event");
103     }
104 }
105 
RegisterNiResponseEvent()106 void AGnssNiManager::RegisterNiResponseEvent()
107 {
108     MatchingSkills matchingSkills;
109     matchingSkills.AddEvent(AGNSS_NI_ACCEPT_EVENT);
110     matchingSkills.AddEvent(AGNSS_NI_REJECT_EVENT);
111     CommonEventSubscribeInfo subscriberInfo(matchingSkills);
112     subscriberInfo.SetPermission("ohos.permission.PUBLISH_LOCATION_EVENT");
113     niResponseSubscriber_ = std::make_shared<GnssCommonEventSubscriber>(subscriberInfo);
114 
115     uint32_t count = 0;
116     bool result = false;
117     while (!result && count <= MAX_RETRY_TIMES) {
118         result = CommonEventManager::SubscribeCommonEvent(niResponseSubscriber_);
119         count++;
120     }
121     if (count > MAX_RETRY_TIMES || !result) {
122         LBSLOGE(GNSS, "Failed to subscriber ni response event");
123     } else {
124         LBSLOGI(GNSS, "success to subscriber ni response event");
125     }
126 }
127 
Run()128 void AGnssNiManager::Run()
129 {
130     LBSLOGI(GNSS, "AGNSS-NI: Run");
131     RegisterAgnssNiEvent();
132     RegisterNiResponseEvent();
133     gnssInterface_ = HDI::Location::Gnss::V2_0::IGnssInterface::Get();
134     if (gnssInterface_ == nullptr) {
135         auto gnssAbility = GnssAbility::GetInstance();
136         if (gnssAbility == nullptr) {
137             LBSLOGE(GNSS, "AGNSS-NI: gnss ability is nullptr");
138             return;
139         }
140         if (!gnssAbility->CheckIfHdiConnected()) {
141             gnssAbility->ConnectHdi();
142             gnssInterface_ = HDI::Location::Gnss::V2_0::IGnssInterface::Get();
143         }
144     }
145 }
146 
UnRegisterAgnssNiEvent()147 void AGnssNiManager::UnRegisterAgnssNiEvent()
148 {
149     if (subscriber_ == nullptr) {
150         LBSLOGE(GNSS, "UnRegisterAgnssNiEvent subscriber_ is null");
151         return;
152     }
153     bool result = CommonEventManager::UnSubscribeCommonEvent(subscriber_);
154     subscriber_ = nullptr;
155     LBSLOGI(GNSS, "unSubscriber gnss event, result = %{public}d", result);
156 }
157 
UnRegisterNiResponseEvent()158 void AGnssNiManager::UnRegisterNiResponseEvent()
159 {
160     if (niResponseSubscriber_ == nullptr) {
161         LBSLOGE(GNSS, "UnRegisterAgnssNiEvent subscriber_ is null");
162         return;
163     }
164     bool result = CommonEventManager::UnSubscribeCommonEvent(niResponseSubscriber_);
165     niResponseSubscriber_ = nullptr;
166     LBSLOGI(GNSS, "unSubscriber ni response event, result = %{public}d", result);
167 }
168 
AgnssNiSuplInit()169 void AGnssNiManager::AgnssNiSuplInit()
170 {
171 #ifdef HDF_DRIVERS_INTERFACE_AGNSS_ENABLE
172     auto gnssAbility = GnssAbility::GetInstance();
173     if (gnssAbility != nullptr) {
174         gnssAbility->SetAgnssServer();
175     }
176 #endif
177 }
178 
179 #ifdef SMS_MMS_ENABLE
IsFromDefaultSubId(const OHOS::EventFwk::Want & want)180 static bool IsFromDefaultSubId(const OHOS::EventFwk::Want &want)
181 {
182     int32_t subId = want.GetIntParam("slotId", INVALID_SUBID);
183     auto msgManager = DelayedSingleton<Telephony::SmsServiceManagerClient>::GetInstance();
184     if (msgManager == nullptr) {
185         LBSLOGE(GNSS, "short message manager nullptr");
186         return false;
187     }
188     int32_t defaultId = msgManager->GetDefaultSmsSlotId();
189     LBSLOGD(GNSS, "current subId %{public}d, defaultSubId %{public}d", subId, defaultId);
190     if (subId != INVALID_SUBID && subId != defaultId) {
191         return false;
192     }
193     return true;
194 }
195 #endif
196 
CheckWapSuplInit(const EventFwk::Want & want)197 void AGnssNiManager::CheckWapSuplInit(const EventFwk::Want &want)
198 {
199 #ifdef SMS_MMS_ENABLE
200     AgnssNiSuplInit();
201     if (!IsFromDefaultSubId(want)) {
202         LBSLOGE(GNSS, "supl init message does not come from default sub");
203         return;
204     }
205 
206     std::string applicationId = want.GetStringParam("applicationId");
207     /*
208      * The WAP application id SHALL be as registered with OMNA (URN: x-oma-application:ulp.ua)
209      * and the assigned code value is (0x10).
210      */
211     if (!(applicationId == "16" || applicationId == URN_APPLICATION_ID)) {
212         LBSLOGE(GNSS, "supl init message application Id %{public}s", applicationId.c_str());
213         return;
214     }
215 
216     std::string rawData = want.GetStringParam("rawData");
217     if (gnssInterface_ == nullptr) {
218         LBSLOGE(GNSS, "gnssInterfacev1_0 is nullptr");
219         return;
220     }
221     gnssInterface_->SendNetworkInitiatedMsg(rawData, rawData.length());
222 #endif
223 }
224 
CheckSmsSuplInit(const EventFwk::Want & want)225 void AGnssNiManager::CheckSmsSuplInit(const EventFwk::Want &want)
226 {
227 #ifdef SMS_MMS_ENABLE
228     AgnssNiSuplInit();
229     if (!IsFromDefaultSubId(want)) {
230         LBSLOGE(GNSS, "supl init message does not come from default sub");
231         return;
232     }
233 
234     std::vector<std::string> pdus = want.GetStringArrayParam(std::string("pdus"));
235     if (pdus.empty()) {
236         LBSLOGI(GNSS, "pdus is null");
237         return;
238     }
239     bool isCdma = want.GetBoolParam("isCdma", false);
240     std::vector<unsigned char> pdu = StringUtils::HexToByteVector(pdus[0]);
241     auto message = new Telephony::ShortMessage();
242     std::u16string netType = isCdma ? u"3gpp2" : u"3gpp";
243     Telephony::ShortMessage::CreateMessage(pdu, netType, *message);
244 
245     if (message != nullptr) {
246         std::string rawUserData = StringUtils::StringToHex(message->GetRawUserData());
247         if (gnssInterface_ == nullptr) {
248             LBSLOGE(GNSS, "gnssInterfacev1_0 is nullptr");
249             delete message;
250             message = nullptr;
251             return;
252         }
253         gnssInterface_->SendNetworkInitiatedMsg(rawUserData, rawUserData.length());
254         delete message;
255         message = nullptr;
256     }
257 #endif
258 }
259 
IsInEmergency()260 bool AGnssNiManager::IsInEmergency()
261 {
262     std::unique_lock<std::mutex> lock(callStateMutex_);
263     bool isInEmergencyExtension = (emergencyCallEndTime_ > 0) &&
264         ((CommonUtils::GetCurrentTime() - emergencyCallEndTime_) < TIME_AFTER_EMERGENCY_CALL);
265 
266     return isInEmergencyCall_ || isInEmergencyExtension;
267 }
268 
OnCallStateChanged(const EventFwk::Want & want)269 void AGnssNiManager::OnCallStateChanged(const EventFwk::Want &want)
270 {
271 #ifdef CALL_MANAGER_ENABLE
272     int32_t state = want.GetIntParam("state", (int32_t)Telephony::TelCallState::CALL_STATUS_UNKNOWN);
273     if (state == (int32_t)Telephony::TelCallState::CALL_STATUS_DIALING) {
274         int32_t slotId = want.GetIntParam("slotId", -1);
275         std::string phoneNumber = want.GetStringParam("number");
276         auto tmpPhoneNumber = Str8ToStr16(phoneNumber);
277         std::unique_lock<std::mutex> lock(callStateMutex_);
278         auto clientPtr = DelayedSingleton<Telephony::CallManagerClient>::GetInstance();
279         if (clientPtr == nullptr) {
280             return;
281         }
282         clientPtr->Init(OHOS::TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID);
283         clientPtr->IsEmergencyPhoneNumber(tmpPhoneNumber, slotId, isInEmergencyCall_);
284         if (isInEmergencyCall_) {
285             emergencyCallEndTime_ = CommonUtils::GetCurrentTime();
286             isInEmergencyCall_ = false;
287         }
288     }
289     return;
290 #endif
291 }
292 
BuildStartCommand(const GnssNiNotificationRequest & notif)293 std::string AGnssNiManager::BuildStartCommand(const GnssNiNotificationRequest &notif)
294 {
295     nlohmann::json param;
296     std::string uiType = "sysDialog/common";
297     param["ability.want.params.uiExtensionType"] = uiType;
298     std::string message = DecodeNiString(notif.supplicantInfo, notif.supplicantInfoEncoding) +
299         DecodeNiString(notif.notificationText, notif.notificationTextEncoding);
300     param["message"] = message;
301     std::string cmdData = param.dump();
302     LBSLOGD(GNSS, "cmdData is: %{public}s.", cmdData.c_str());
303     return cmdData;
304 }
305 
ConnectExtensionAbility(const AAFwk::Want & want,const std::string & commandStr)306 static void ConnectExtensionAbility(const AAFwk::Want &want, const std::string &commandStr)
307 {
308     std::string bundleName = LOCATION_DIALOG_BUNDLE_NAME;
309     std::string abilityName = AGNSS_NI_DIALOG_ABILITY_NAME;
310     sptr<UIExtensionAbilityConnection> connection(
311         new (std::nothrow) UIExtensionAbilityConnection(commandStr, bundleName, abilityName));
312     if (connection == nullptr) {
313         LBSLOGE(GNSS, "connect UIExtensionAbilityConnection fail");
314         return;
315     }
316 
317     std::string identity = IPCSkeleton::ResetCallingIdentity();
318     auto ret =
319         AAFwk::ExtensionManagerClient::GetInstance().ConnectServiceExtensionAbility(want, connection, nullptr, -1);
320     LBSLOGI(GNSS, "connect service extension ability result = %{public}d", ret);
321     IPCSkeleton::SetCallingIdentity(identity);
322     return;
323 }
324 
OpenNiDialog(const GnssNiNotificationRequest & notif)325 void AGnssNiManager::OpenNiDialog(const GnssNiNotificationRequest &notif)
326 {
327     LBSLOGI(GNSS, "ConnectExtension");
328     AAFwk::Want want;
329     std::string bundleName = "com.ohos.sceneboard";
330     std::string abilityName = "com.ohos.sceneboard.systemdialog";
331     want.SetElementName(bundleName, abilityName);
332     std::string connectStr = BuildStartCommand(notif);
333     ConnectExtensionAbility(want, connectStr);
334 }
335 
DecodeNiString(std::string original,int coding)336 std::string AGnssNiManager::DecodeNiString(std::string original, int coding)
337 {
338     if (coding == GNSS_NI_ENCODING_FORMAT_NULL) {
339         return original;
340     }
341 
342     std::string tmp = StringUtils::HexToString(original);
343     switch (coding) {
344         case GNSS_NI_ENCODING_FORMAT_SUPL_GSM_DEFAULT: {
345             return StringUtils::Gsm7Decode(tmp);
346         }
347         case GNSS_NI_ENCODING_FORMAT_SUPL_UCS2: {
348             std::wstring decodedUCS2String = StringUtils::Ucs2ToWstring(tmp);
349             return StringUtils::WstringToString(decodedUCS2String);
350         }
351         case GNSS_NI_ENCODING_FORMAT_SUPL_UTF8: {
352             std::wstring decodedUTF8String = StringUtils::Utf8ToWstring(tmp);
353             return StringUtils::WstringToString(decodedUTF8String);
354         }
355         default: {
356             LBSLOGE(GNSS, "unknow encoding %{public}d for NI text %{public}s", coding, original.c_str());
357             return original;
358         }
359     }
360 }
361 
SendNiNotification(const GnssNiNotificationRequest & notif)362 void AGnssNiManager::SendNiNotification(const GnssNiNotificationRequest &notif)
363 {
364 #ifdef NOTIFICATION_ENABLE
365     std::shared_ptr<Notification::NotificationNormalContent> notificationNormalContent =
366         std::make_shared<Notification::NotificationNormalContent>();
367     if (notificationNormalContent == nullptr) {
368         LBSLOGE(GNSS, "get notification normal content nullptr");
369         return;
370     }
371 
372     std::string title = "Location Request";
373     std::string msgBody = DecodeNiString(notif.supplicantInfo, notif.supplicantInfoEncoding) +
374         DecodeNiString(notif.notificationText, notif.notificationTextEncoding);
375     if (msgBody.empty()) {
376         msgBody = "SUPL Service";
377     }
378     std::string message = "Requested by " + msgBody;
379     notificationNormalContent->SetTitle(title);
380     notificationNormalContent->SetText(message);
381     std::shared_ptr<OHOS::Notification::NotificationContent> notificationContent =
382         std::make_shared<OHOS::Notification::NotificationContent>(notificationNormalContent);
383 
384     if (notificationContent == nullptr) {
385         LBSLOGE(GNSS, "get notification content nullptr");
386         return;
387     }
388 
389     Notification::NotificationRequest request;
390     request.SetNotificationId(GNSS_AGNSS_NI_NOTIFICATION_ID);
391     request.SetContent(notificationContent);
392     request.SetCreatorUid(LOCATION_GNSS_SA_ID);
393     request.SetAutoDeletedTime(NOTIFICATION_AUTO_DELETED_TIME);
394     request.SetTapDismissed(true);
395     request.SetCreatorBundleName(AGNSS_NI_SERVICE_NAME);
396     request.SetSlotType(Notification::NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
397 
398     int32_t ret = Notification::NotificationHelper::PublishNotification(request);
399     if (ret != 0) {
400         LBSLOGE(GNSS, "Publish Notification errorCode = %{public}d", ret);
401         return;
402     }
403     LBSLOGI(GNSS, "GNSS service publish notification success");
404 #else
405     LBSLOGI(GNSS, "GNSS service publish notification not support");
406 #endif
407 }
408 
SendUserResponse(GnssNiResponseCmd responseCmd)409 void AGnssNiManager::SendUserResponse(GnssNiResponseCmd responseCmd)
410 {
411     std::unique_lock<std::mutex> lock(mutex_);
412     if (gnssInterface_ == nullptr) {
413         LBSLOGE(GNSS, "gnssInterfacev1_0 is nullptr");
414         return;
415     }
416     gnssInterface_->SendNiUserResponse(niNotificationId_, responseCmd);
417 }
418 
HandleNiNotification(const GnssNiNotificationRequest & notif)419 void AGnssNiManager::HandleNiNotification(const GnssNiNotificationRequest &notif)
420 {
421     std::unique_lock<std::mutex> lock(mutex_);
422     niNotificationId_ = notif.gnssNiNotificationId;
423     bool needNotify = (notif.notificationCategory & GNSS_NI_NOTIFICATION_REQUIRE_NOTIFY) != 0;
424     bool needVerify = (notif.notificationCategory & GNSS_NI_NOTIFICATION_REQUIRE_VERIFY) != 0;
425     bool privacyOverride = (notif.notificationCategory & GNSS_NI_NOTIFICATION_REQUIRE_PRIVACY_OVERRIDE) != 0;
426     if (LocationDataRdbManager::QuerySwitchState() != ENABLED && !IsInEmergency()) {
427         SendUserResponse(GNSS_NI_RESPONSE_CMD_NO_RESPONSE);
428     }
429 
430     if (needNotify) {
431         if (needVerify) {
432             OpenNiDialog(notif);
433         } else {
434             SendNiNotification(notif);
435             SendUserResponse(GNSS_NI_RESPONSE_CMD_ACCEPT);
436         }
437     }
438 
439     if (!needNotify || privacyOverride) {
440         SendUserResponse(GNSS_NI_RESPONSE_CMD_ACCEPT);
441     }
442 }
443 
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)444 void SystemAbilityStatusChangeListener::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
445 {
446     LBSLOGI(GNSS, "AGNSS-NI systemAbilityId:%{public}d", systemAbilityId);
447     if (systemAbilityId != COMMON_EVENT_SERVICE_ID) {
448         LBSLOGE(GNSS, "systemAbilityId is not COMMON_EVENT_SERVICE_ID");
449         return;
450     }
451     auto agnssNiManager = AGnssNiManager::GetInstance();
452     if (agnssNiManager == nullptr) {
453         LBSLOGE(GNSS, "agnssNiManager nullptr");
454         return;
455     }
456     agnssNiManager->Run();
457 
458     return;
459 }
460 
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)461 void SystemAbilityStatusChangeListener::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
462 {
463     LBSLOGI(GNSS, "AGNSS-NI systemAbilityId:%{public}d", systemAbilityId);
464     if (systemAbilityId != COMMON_EVENT_SERVICE_ID) {
465         LBSLOGE(GNSS, "systemAbilityId is not COMMON_EVENT_SERVICE_ID");
466         return;
467     }
468     auto agnssNiManager = AGnssNiManager::GetInstance();
469     if (agnssNiManager == nullptr) {
470         LBSLOGE(GNSS, "agnssNiManager nullptr");
471         return;
472     }
473     agnssNiManager->UnRegisterAgnssNiEvent();
474     agnssNiManager->UnRegisterNiResponseEvent();
475     return;
476 }
477 
478 }  // namespace Location
479 }  // namespace OHOS
480 #endif
481