1 /*
2  * Copyright (C) 2022 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_GEOCODE_SUPPORT
17 #include "geo_convert_service.h"
18 #include <file_ex.h>
19 #include <thread>
20 #include "ability_connect_callback_stub.h"
21 #include "ability_manager_client.h"
22 #include "geo_address.h"
23 #include "geo_convert_request.h"
24 #include "common_utils.h"
25 #include "location_config_manager.h"
26 #include "location_dumper.h"
27 #include "location_sa_load_manager.h"
28 #include "system_ability_definition.h"
29 
30 namespace OHOS {
31 namespace Location {
32 const bool REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(
33     GeoConvertService::GetInstance());
34 const uint32_t EVENT_SEND_GEOREQUEST = 0x0100;
35 const char* UNLOAD_GEOCONVERT_TASK = "geoconvert_sa_unload";
36 const int GEOCONVERT_CONNECT_TIME_OUT = 1;
37 const uint32_t EVENT_INTERVAL_UNITE = 1000;
38 const int UNLOAD_GEOCONVERT_DELAY_TIME = 5 * EVENT_INTERVAL_UNITE;
GetInstance()39 GeoConvertService* GeoConvertService::GetInstance()
40 {
41     static GeoConvertService data;
42     return &data;
43 }
44 
GeoConvertService()45 GeoConvertService::GeoConvertService() : SystemAbility(LOCATION_GEO_CONVERT_SA_ID, true)
46 {
47     geoConvertHandler_ =
48         std::make_shared<GeoConvertHandler>(AppExecFwk::EventRunner::Create(true, AppExecFwk::ThreadMode::FFRT));
49     LBSLOGI(GEO_CONVERT, "GeoConvertService constructed.");
50 }
51 
~GeoConvertService()52 GeoConvertService::~GeoConvertService()
53 {
54     if (geoConvertHandler_ != nullptr) {
55         geoConvertHandler_->RemoveTask(UNLOAD_GEOCONVERT_TASK);
56     }
57     conn_ = nullptr;
58 }
59 
OnStart()60 void GeoConvertService::OnStart()
61 {
62     if (state_ == ServiceRunningState::STATE_RUNNING) {
63         LBSLOGI(GEO_CONVERT, "GeoConvertService has already started.");
64         return;
65     }
66     if (!Init()) {
67         LBSLOGE(GEO_CONVERT, "failed to init GeoConvertService");
68         OnStop();
69         return;
70     }
71     state_ = ServiceRunningState::STATE_RUNNING;
72     LBSLOGI(GEO_CONVERT, "GeoConvertService::OnStart start service success.");
73 }
74 
OnStop()75 void GeoConvertService::OnStop()
76 {
77     state_ = ServiceRunningState::STATE_NOT_START;
78     registerToService_ = false;
79     if (conn_ != nullptr) {
80         AAFwk::AbilityManagerClient::GetInstance()->DisconnectAbility(conn_);
81         LBSLOGD(GEO_CONVERT, "GeoConvertService::OnStop and disconnect");
82         UnRegisterGeoServiceDeathRecipient();
83         SetServiceConnectState(ServiceConnectState::STATE_DISCONNECT);
84     }
85     LBSLOGI(GEO_CONVERT, "GeoConvertService::OnStop service stopped.");
86 }
87 
Init()88 bool GeoConvertService::Init()
89 {
90     if (!registerToService_) {
91         bool ret = Publish(AsObject());
92         if (!ret) {
93             LBSLOGE(GEO_CONVERT, "GeoConvertService::Init Publish failed!");
94             return false;
95         }
96         registerToService_ = true;
97     }
98     return true;
99 }
100 
101 class AbilityConnection : public AAFwk::AbilityConnectionStub {
102 public:
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)103     void OnAbilityConnectDone(
104         const AppExecFwk::ElementName& element, const sptr<IRemoteObject>& remoteObject, int resultCode) override
105     {
106         std::string uri = element.GetURI();
107         LBSLOGD(GEO_CONVERT, "Connected uri is %{public}s, result is %{public}d.", uri.c_str(), resultCode);
108         if (resultCode != ERR_OK) {
109             return;
110         }
111         GeoConvertService::GetInstance()->NotifyConnected(remoteObject);
112     }
113 
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int)114     void OnAbilityDisconnectDone(const AppExecFwk::ElementName& element, int) override
115     {
116         std::string uri = element.GetURI();
117         LBSLOGD(GEO_CONVERT, "Disconnected uri is %{public}s.", uri.c_str());
118         GeoConvertService::GetInstance()->NotifyDisConnected();
119     }
120 };
121 
ConnectService()122 bool GeoConvertService::ConnectService()
123 {
124     LBSLOGD(GEO_CONVERT, "start ConnectService");
125     AAFwk::Want connectionWant;
126     std::string serviceName;
127     bool result = LocationConfigManager::GetInstance()->GetGeocodeServiceName(serviceName);
128     if (!result || serviceName.empty()) {
129         LBSLOGE(GEO_CONVERT, "get service name failed!");
130         return false;
131     }
132     std::string abilityName;
133     bool res = LocationConfigManager::GetInstance()->GetGeocodeAbilityName(abilityName);
134     if (!res || abilityName.empty()) {
135         LBSLOGE(GEO_CONVERT, "get service name failed!");
136         return false;
137     }
138     connectionWant.SetElementName(serviceName, abilityName);
139     conn_ = sptr<AAFwk::IAbilityConnection>(new (std::nothrow) AbilityConnection());
140     if (conn_ == nullptr) {
141         LBSLOGE(GEO_CONVERT, "get connection failed!");
142         return false;
143     }
144     SetServiceConnectState(ServiceConnectState::STATE_CONNECTTING);
145     int32_t ret = AAFwk::AbilityManagerClient::GetInstance()->ConnectAbility(connectionWant, conn_, -1);
146     if (ret != ERR_OK) {
147         LBSLOGE(GEO_CONVERT, "Connect cloud service failed!");
148         return false;
149     }
150     std::unique_lock<std::mutex> uniqueLock(mutex_);
151     auto waitStatus =
152         connectCondition_.wait_for(uniqueLock,
153         std::chrono::seconds(GEOCONVERT_CONNECT_TIME_OUT), [this]() { return serviceProxy_ != nullptr; });
154     if (!waitStatus) {
155         LBSLOGE(GEO_CONVERT, "Connect cloudService timeout!");
156         SetServiceConnectState(ServiceConnectState::STATE_DISCONNECT);
157         return false;
158     }
159     SetServiceConnectState(ServiceConnectState::STATE_CONNECTTED);
160     RegisterGeoServiceDeathRecipient();
161     return true;
162 }
163 
NotifyConnected(const sptr<IRemoteObject> & remoteObject)164 void GeoConvertService::NotifyConnected(const sptr<IRemoteObject>& remoteObject)
165 {
166     std::unique_lock<std::mutex> uniqueLock(mutex_);
167     serviceProxy_ = remoteObject;
168     connectCondition_.notify_all();
169 }
170 
NotifyDisConnected()171 void GeoConvertService::NotifyDisConnected()
172 {
173     std::unique_lock<std::mutex> uniqueLock(mutex_);
174     serviceProxy_ = nullptr;
175     connectCondition_.notify_all();
176 }
177 
IsGeoConvertAvailable(MessageParcel & reply)178 int GeoConvertService::IsGeoConvertAvailable(MessageParcel &reply)
179 {
180     std::string serviceName;
181     bool result = LocationConfigManager::GetInstance()->GetGeocodeServiceName(serviceName);
182     if (!result || serviceName.empty()) {
183         LBSLOGE(GEO_CONVERT, "get service name failed!");
184         reply.WriteInt32(ERRCODE_SUCCESS);
185         reply.WriteBool(false);
186         return ERRCODE_SUCCESS;
187     }
188     reply.WriteInt32(ERRCODE_SUCCESS);
189     if (!CommonUtils::CheckAppInstalled(serviceName)) { // app is not installed
190         reply.WriteBool(false);
191     } else {
192         reply.WriteBool(true);
193     }
194     return ERRCODE_SUCCESS;
195 }
196 
GetAddressByCoordinate(MessageParcel & data,MessageParcel & reply)197 int GeoConvertService::GetAddressByCoordinate(MessageParcel &data, MessageParcel &reply)
198 {
199     if (mockEnabled_) {
200         ReportAddressMock(data, reply);
201         return ERRCODE_SUCCESS;
202     }
203     if (!GetService()) {
204         reply.WriteInt32(ERRCODE_REVERSE_GEOCODING_FAIL);
205         return ERRCODE_REVERSE_GEOCODING_FAIL;
206     }
207     GeoCodeType requestType = GeoCodeType::REQUEST_REVERSE_GEOCODE;
208     auto geoConvertRequest = GeoConvertRequest::Unmarshalling(data, requestType);
209     AppExecFwk::InnerEvent::Pointer event = AppExecFwk::InnerEvent::
210         Get(EVENT_SEND_GEOREQUEST, geoConvertRequest);
211     if (geoConvertHandler_ != nullptr) {
212         geoConvertHandler_->SendEvent(event);
213     }
214     return ERRCODE_SUCCESS;
215 }
216 
ReportAddressMock(MessageParcel & data,MessageParcel & reply)217 void GeoConvertService::ReportAddressMock(MessageParcel &data, MessageParcel &reply)
218 {
219     int arraySize = 0;
220     std::vector<std::shared_ptr<GeoAddress>> array;
221     ReverseGeocodeRequest request;
222     request.latitude = data.ReadDouble();
223     request.longitude = data.ReadDouble();
224     request.maxItems = data.ReadInt32();
225     data.ReadInt32(); // locale size
226     request.locale = Str16ToStr8(data.ReadString16());
227     std::unique_lock<std::mutex> lock(mockInfoMutex_, std::defer_lock);
228     lock.lock();
229     for (size_t i = 0; i < mockInfo_.size(); i++) {
230         std::shared_ptr<GeocodingMockInfo> info = mockInfo_[i];
231         if (!CommonUtils::DoubleEqual(request.latitude, info->GetLocation()->latitude) ||
232             !CommonUtils::DoubleEqual(request.longitude, info->GetLocation()->longitude)) {
233             continue;
234         }
235         arraySize++;
236         array.push_back(info->GetGeoAddressInfo());
237     }
238     lock.unlock();
239     reply.WriteInt32(ERRCODE_SUCCESS);
240     if (arraySize > 0) {
241         reply.WriteInt32(arraySize);
242         for (size_t i = 0; i < array.size(); i++) {
243             array[i]->Marshalling(reply);
244         }
245     } else {
246         reply.WriteInt32(0);
247     }
248 }
249 
GetAddressByLocationName(MessageParcel & data,MessageParcel & reply)250 int GeoConvertService::GetAddressByLocationName(MessageParcel &data, MessageParcel &reply)
251 {
252     if (!GetService()) {
253         reply.WriteInt32(ERRCODE_GEOCODING_FAIL);
254         return ERRCODE_GEOCODING_FAIL;
255     }
256     GeoCodeType requestType = GeoCodeType::REQUEST_GEOCODE;
257     auto geoConvertRequest = GeoConvertRequest::Unmarshalling(data, requestType);
258     AppExecFwk::InnerEvent::Pointer event = AppExecFwk::InnerEvent::
259         Get(EVENT_SEND_GEOREQUEST, geoConvertRequest);
260     if (geoConvertHandler_ != nullptr) {
261         geoConvertHandler_->SendEvent(event);
262     }
263     return ERRCODE_SUCCESS;
264 }
265 
GetService()266 bool GeoConvertService::GetService()
267 {
268     if (!IsConnect() && !IsConnecting()) {
269         std::string serviceName;
270         bool result = LocationConfigManager::GetInstance()->GetGeocodeServiceName(serviceName);
271         if (!result || serviceName.empty()) {
272             LBSLOGE(GEO_CONVERT, "get service name failed!");
273             return false;
274         }
275         if (!CommonUtils::CheckAppInstalled(serviceName)) { // app is not installed
276             LBSLOGE(GEO_CONVERT, "service is not available.");
277             return false;
278         } else if (!ConnectService()) {
279             return false;
280         }
281     }
282     return true;
283 }
284 
IsConnect()285 bool GeoConvertService::IsConnect()
286 {
287     std::unique_lock<std::mutex> uniqueLock(mutex_);
288     return serviceProxy_ != nullptr &&
289         GetServiceConnectState() == ServiceConnectState::STATE_CONNECTTED;
290 }
291 
EnableReverseGeocodingMock()292 bool GeoConvertService::EnableReverseGeocodingMock()
293 {
294     LBSLOGD(GEO_CONVERT, "EnableReverseGeocodingMock");
295     mockEnabled_ = true;
296     return true;
297 }
298 
DisableReverseGeocodingMock()299 bool GeoConvertService::DisableReverseGeocodingMock()
300 {
301     LBSLOGD(GEO_CONVERT, "DisableReverseGeocodingMock");
302     mockEnabled_ = false;
303     return true;
304 }
305 
SetReverseGeocodingMockInfo(std::vector<std::shared_ptr<GeocodingMockInfo>> & mockInfo)306 LocationErrCode GeoConvertService::SetReverseGeocodingMockInfo(
307     std::vector<std::shared_ptr<GeocodingMockInfo>>& mockInfo)
308 {
309     LBSLOGD(GEO_CONVERT, "SetReverseGeocodingMockInfo");
310     std::unique_lock<std::mutex> lock(mockInfoMutex_, std::defer_lock);
311     lock.lock();
312     mockInfo_.assign(mockInfo.begin(), mockInfo.end());
313     lock.unlock();
314     return ERRCODE_SUCCESS;
315 }
316 
CancelIdleState()317 bool GeoConvertService::CancelIdleState()
318 {
319     bool ret = CancelIdle();
320     if (!ret) {
321         LBSLOGE(GEO_CONVERT, "%{public}s cancel idle failed!", __func__);
322         return false;
323     }
324     return true;
325 }
326 
UnloadGeoConvertSystemAbility()327 void GeoConvertService::UnloadGeoConvertSystemAbility()
328 {
329     if (geoConvertHandler_ == nullptr) {
330         LBSLOGE(GEO_CONVERT, "%{public}s geoConvertHandler_ is nullptr", __func__);
331         return;
332     }
333     geoConvertHandler_->RemoveTask(UNLOAD_GEOCONVERT_TASK);
334     if (CheckIfGeoConvertConnecting()) {
335         return;
336     }
337     auto task = [this]() {
338         SaLoadWithStatistic::UnInitLocationSa(LOCATION_GEO_CONVERT_SA_ID);
339         GeoConvertService::GetInstance()->DisconnectAbilityConnect();
340     };
341     geoConvertHandler_->PostTask(task, UNLOAD_GEOCONVERT_TASK, UNLOAD_GEOCONVERT_DELAY_TIME);
342 }
343 
DisconnectAbilityConnect()344 void GeoConvertService::DisconnectAbilityConnect()
345 {
346     if (conn_ != nullptr) {
347         AAFwk::AbilityManagerClient::GetInstance()->DisconnectAbility(conn_);
348         SetServiceConnectState(ServiceConnectState::STATE_DISCONNECT);
349         LBSLOGI(GEO_CONVERT, "UnloadGeoConvert OnStop and disconnect");
350     }
351 }
352 
CheckIfGeoConvertConnecting()353 bool GeoConvertService::CheckIfGeoConvertConnecting()
354 {
355     return mockEnabled_;
356 }
357 
SaDumpInfo(std::string & result)358 void GeoConvertService::SaDumpInfo(std::string& result)
359 {
360     result += "GeoConvert enable status: false";
361     result += "\n";
362 }
363 
Dump(int32_t fd,const std::vector<std::u16string> & args)364 int32_t GeoConvertService::Dump(int32_t fd, const std::vector<std::u16string>& args)
365 {
366     std::vector<std::string> vecArgs;
367     std::transform(args.begin(), args.end(), std::back_inserter(vecArgs), [](const std::u16string &arg) {
368         return Str16ToStr8(arg);
369     });
370 
371     LocationDumper dumper;
372     std::string result;
373     dumper.GeocodeDump(SaDumpInfo, vecArgs, result);
374     if (!SaveStringToFd(fd, result)) {
375         LBSLOGE(GEO_CONVERT, "Geocode save string to fd failed!");
376         return ERR_OK;
377     }
378     return ERR_OK;
379 }
380 
ResetServiceProxy()381 bool GeoConvertService::ResetServiceProxy()
382 {
383     std::unique_lock<std::mutex> uniqueLock(mutex_);
384     serviceProxy_ = nullptr;
385     return true;
386 }
387 
RegisterGeoServiceDeathRecipient()388 void GeoConvertService::RegisterGeoServiceDeathRecipient()
389 {
390     if (serviceProxy_ == nullptr) {
391         LBSLOGE(GEO_CONVERT, "%{public}s: geoServiceProxy_ is nullptr", __func__);
392         return;
393     }
394     if (geoServiceRecipient_ != nullptr) {
395         serviceProxy_->AddDeathRecipient(geoServiceRecipient_);
396     }
397 }
398 
UnRegisterGeoServiceDeathRecipient()399 void GeoConvertService::UnRegisterGeoServiceDeathRecipient()
400 {
401     std::unique_lock<std::mutex> uniqueLock(mutex_);
402     if (serviceProxy_ == nullptr) {
403         LBSLOGE(GEO_CONVERT, "%{public}s: geoServiceProxy_ is nullptr", __func__);
404         return;
405     }
406     if (geoServiceRecipient_ != nullptr) {
407         serviceProxy_->RemoveDeathRecipient(geoServiceRecipient_);
408         geoServiceRecipient_ = nullptr;
409     }
410 }
411 
SendGeocodeRequest(int code,MessageParcel & dataParcel,MessageParcel & replyParcel,MessageOption & option)412 bool GeoConvertService::SendGeocodeRequest(int code, MessageParcel& dataParcel, MessageParcel& replyParcel,
413     MessageOption& option)
414 {
415     std::unique_lock<std::mutex> uniqueLock(mutex_);
416     if (serviceProxy_ == nullptr) {
417         LBSLOGE(GEO_CONVERT, "serviceProxy is nullptr!");
418         return false;
419     }
420     MessageParcel data;
421     data.WriteInterfaceToken(serviceProxy_->GetInterfaceDescriptor());
422     data.Append(dataParcel);
423     int error = serviceProxy_->SendRequest(code, data, replyParcel, option);
424     if (error != ERR_OK) {
425         LBSLOGE(GEO_CONVERT, "SendRequest to cloud service failed. error = %{public}d", error);
426         return false;
427     }
428     return true;
429 }
430 
GetServiceConnectState()431 ServiceConnectState GeoConvertService::GetServiceConnectState()
432 {
433     std::unique_lock<std::mutex> uniqueLock(connectStateMutex_);
434     return connectState_;
435 }
436 
SetServiceConnectState(ServiceConnectState connectState)437 void GeoConvertService::SetServiceConnectState(ServiceConnectState connectState)
438 {
439     std::unique_lock<std::mutex> uniqueLock(connectStateMutex_);
440     connectState_ = connectState;
441 }
442 
IsConnecting()443 bool GeoConvertService::IsConnecting()
444 {
445     std::unique_lock<std::mutex> uniqueLock(connectStateMutex_);
446     return connectState_ == ServiceConnectState::STATE_CONNECTTING;
447 }
448 
GeoServiceDeathRecipient()449 GeoServiceDeathRecipient::GeoServiceDeathRecipient()
450 {
451 }
452 
~GeoServiceDeathRecipient()453 GeoServiceDeathRecipient::~GeoServiceDeathRecipient()
454 {
455 }
456 
OnRemoteDied(const wptr<IRemoteObject> & remote)457 void GeoServiceDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
458 {
459     auto geoConvertService = GeoConvertService::GetInstance();
460     if (geoConvertService != nullptr) {
461         LBSLOGI(GEO_CONVERT, "geo OnRemoteDied");
462         geoConvertService->ResetServiceProxy();
463         geoConvertService->SetServiceConnectState(ServiceConnectState::STATE_DISCONNECT);
464     }
465 }
466 
GeoConvertHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner)467 GeoConvertHandler::GeoConvertHandler(const std::shared_ptr<AppExecFwk::EventRunner>& runner) : EventHandler(runner) {}
468 
~GeoConvertHandler()469 GeoConvertHandler::~GeoConvertHandler() {}
470 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)471 void GeoConvertHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer& event)
472 {
473     auto geoConvertService = GeoConvertService::GetInstance();
474     if (geoConvertService == nullptr) {
475         LBSLOGE(NETWORK, "ProcessEvent: GeoConvertService is nullptr");
476         return;
477     }
478     uint32_t eventId = event->GetInnerEventId();
479     LBSLOGD(GEO_CONVERT, "ProcessEvent event:%{public}d", eventId);
480     switch (eventId) {
481         case EVENT_SEND_GEOREQUEST: {
482             std::unique_ptr<GeoConvertRequest> geoConvertRequest = event->GetUniqueObject<GeoConvertRequest>();
483             if (geoConvertRequest == nullptr) {
484                 return;
485             }
486             MessageParcel dataParcel;
487             MessageParcel replyParcel;
488             MessageOption option;
489             geoConvertRequest->Marshalling(dataParcel);
490             bool ret = geoConvertService->SendGeocodeRequest(static_cast<int>(geoConvertRequest->GetRequestType()),
491                 dataParcel, replyParcel, option);
492             if (!ret) {
493                 LBSLOGE(GEO_CONVERT, "SendGeocodeRequest failed errcode");
494                 return;
495             }
496             break;
497         }
498         default:
499             break;
500     }
501 }
502 } // namespace Location
503 } // namespace OHOS
504 #endif
505