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_interface.h"
21 #include "ability_connect_callback_stub.h"
22 #include "ability_manager_client.h"
23 #include "geo_address.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 DelayedSingleton<GeoConvertService>::GetInstance().get());
34 static constexpr int REQUEST_GEOCODE = 1;
35 static constexpr int REQUEST_REVERSE_GEOCODE = 2;
36 constexpr uint32_t WAIT_MS = 100;
37 const int MAX_RETRY_COUNT = 5;
GeoConvertService()38 GeoConvertService::GeoConvertService() : SystemAbility(LOCATION_GEO_CONVERT_SA_ID, true)
39 {
40 LBSLOGI(GEO_CONVERT, "GeoConvertService constructed.");
41 }
42
~GeoConvertService()43 GeoConvertService::~GeoConvertService()
44 {
45 }
46
OnStart()47 void GeoConvertService::OnStart()
48 {
49 if (state_ == ServiceRunningState::STATE_RUNNING) {
50 LBSLOGI(GEO_CONVERT, "GeoConvertService has already started.");
51 return;
52 }
53 if (!Init()) {
54 LBSLOGE(GEO_CONVERT, "failed to init GeoConvertService");
55 OnStop();
56 return;
57 }
58 state_ = ServiceRunningState::STATE_RUNNING;
59 LBSLOGI(GEO_CONVERT, "GeoConvertService::OnStart start service success.");
60 }
61
OnStop()62 void GeoConvertService::OnStop()
63 {
64 state_ = ServiceRunningState::STATE_NOT_START;
65 registerToService_ = false;
66 LBSLOGI(GEO_CONVERT, "GeoConvertService::OnStop service stopped.");
67 }
68
Init()69 bool GeoConvertService::Init()
70 {
71 if (!registerToService_) {
72 bool ret = Publish(AsObject());
73 if (!ret) {
74 LBSLOGE(GEO_CONVERT, "GeoConvertService::Init Publish failed!");
75 return false;
76 }
77 registerToService_ = true;
78 }
79 return true;
80 }
81
82 class AbilityConnection : public AAFwk::AbilityConnectionStub {
83 public:
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)84 void OnAbilityConnectDone(
85 const AppExecFwk::ElementName& element, const sptr<IRemoteObject>& remoteObject, int resultCode) override
86 {
87 std::string uri = element.GetURI();
88 LBSLOGD(GEO_CONVERT, "Connected uri is %{public}s, result is %{public}d.", uri.c_str(), resultCode);
89 if (resultCode != ERR_OK) {
90 return;
91 }
92 DelayedSingleton<GeoConvertService>::GetInstance().get()->NotifyConnected(remoteObject);
93 }
94
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int)95 void OnAbilityDisconnectDone(const AppExecFwk::ElementName& element, int) override
96 {
97 std::string uri = element.GetURI();
98 LBSLOGD(GEO_CONVERT, "Disconnected uri is %{public}s.", uri.c_str());
99 DelayedSingleton<GeoConvertService>::GetInstance().get()->NotifyDisConnected();
100 }
101 };
102
ReConnectService()103 bool GeoConvertService::ReConnectService()
104 {
105 int retryCount = 0;
106 if (IsConnect()) {
107 LBSLOGI(GEO_CONVERT, "Connect success!");
108 return true;
109 }
110 while (retryCount < MAX_RETRY_COUNT) {
111 retryCount++;
112 bool ret = ConnectService();
113 if (ret) {
114 LBSLOGI(GEO_CONVERT, "Connect success!");
115 return true;
116 }
117 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
118 }
119 return false;
120 }
121
ConnectService()122 bool GeoConvertService::ConnectService()
123 {
124 LBSLOGD(GEO_CONVERT, "start ConnectService");
125 if (!IsConnect()) {
126 AAFwk::Want connectionWant;
127 std::string serviceName;
128 bool result = LocationConfigManager::GetInstance().GetGeocodeServiceName(serviceName);
129 if (!result || serviceName.empty()) {
130 LBSLOGE(GEO_CONVERT, "get service name failed!");
131 return false;
132 }
133 std::string abilityName;
134 bool res = LocationConfigManager::GetInstance().GetGeocodeAbilityName(abilityName);
135 if (!res || abilityName.empty()) {
136 LBSLOGE(GEO_CONVERT, "get service name failed!");
137 return false;
138 }
139 connectionWant.SetElementName(serviceName, abilityName);
140 sptr<AAFwk::IAbilityConnection> conn = new (std::nothrow) AbilityConnection();
141 if (conn == nullptr) {
142 LBSLOGE(GEO_CONVERT, "get connection failed!");
143 return false;
144 }
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 = connectCondition_.wait_for(
152 uniqueLock, std::chrono::seconds(CONNECT_TIME_OUT), [this]() { return serviceProxy_ != nullptr; });
153 if (!waitStatus) {
154 LBSLOGE(GEO_CONVERT, "Connect cloudService timeout!");
155 return false;
156 }
157 }
158 return true;
159 }
160
NotifyConnected(const sptr<IRemoteObject> & remoteObject)161 void GeoConvertService::NotifyConnected(const sptr<IRemoteObject>& remoteObject)
162 {
163 std::unique_lock<std::mutex> uniqueLock(mutex_);
164 serviceProxy_ = remoteObject;
165 connectCondition_.notify_all();
166 }
167
NotifyDisConnected()168 void GeoConvertService::NotifyDisConnected()
169 {
170 std::unique_lock<std::mutex> uniqueLock(mutex_);
171 serviceProxy_ = nullptr;
172 connectCondition_.notify_all();
173 }
174
IsGeoConvertAvailable(MessageParcel & reply)175 int GeoConvertService::IsGeoConvertAvailable(MessageParcel &reply)
176 {
177 std::string serviceName;
178 bool result = LocationConfigManager::GetInstance().GetGeocodeServiceName(serviceName);
179 if (!result || serviceName.empty()) {
180 LBSLOGE(GEO_CONVERT, "get service name failed!");
181 reply.WriteInt32(ERRCODE_SUCCESS);
182 reply.WriteBool(false);
183 return ERRCODE_SUCCESS;
184 }
185 reply.WriteInt32(ERRCODE_SUCCESS);
186 if (!CommonUtils::CheckAppInstalled(serviceName)) { // app is not installed
187 reply.WriteBool(false);
188 } else {
189 reply.WriteBool(true);
190 }
191 return ERRCODE_SUCCESS;
192 }
193
GetAddressByCoordinate(MessageParcel & data,MessageParcel & reply)194 int GeoConvertService::GetAddressByCoordinate(MessageParcel &data, MessageParcel &reply)
195 {
196 if (mockEnabled_) {
197 ReportAddressMock(data, reply);
198 return ERRCODE_SUCCESS;
199 }
200 if (!GetService()) {
201 reply.WriteInt32(ERRCODE_REVERSE_GEOCODING_FAIL);
202 return ERRCODE_REVERSE_GEOCODING_FAIL;
203 }
204
205 MessageParcel dataParcel;
206 MessageParcel replyParcel;
207 MessageOption option;
208
209 if (!WriteInfoToParcel(data, dataParcel, true)) {
210 reply.WriteInt32(ERRCODE_REVERSE_GEOCODING_FAIL);
211 return ERRCODE_REVERSE_GEOCODING_FAIL;
212 }
213 sptr<GeoConvertCallbackHost> callback = new (std::nothrow) GeoConvertCallbackHost();
214 if (callback == nullptr) {
215 LBSLOGE(GEO_CONVERT, "can not get valid callback.");
216 reply.WriteInt32(ERRCODE_REVERSE_GEOCODING_FAIL);
217 return ERRCODE_REVERSE_GEOCODING_FAIL;
218 }
219 dataParcel.WriteRemoteObject(callback->AsObject());
220
221 if (serviceProxy_ == nullptr) {
222 LBSLOGE(GEO_CONVERT, "serviceProxy is nullptr!");
223 reply.WriteInt32(ERRCODE_REVERSE_GEOCODING_FAIL);
224 return ERRCODE_REVERSE_GEOCODING_FAIL;
225 }
226 int error = serviceProxy_->SendRequest(REQUEST_REVERSE_GEOCODE, dataParcel, replyParcel, option);
227 if (error != ERR_OK) {
228 LBSLOGE(GEO_CONVERT, "SendRequest to cloud service failed.");
229 reply.WriteInt32(ERRCODE_REVERSE_GEOCODING_FAIL);
230 return ERRCODE_REVERSE_GEOCODING_FAIL;
231 }
232 std::list<std::shared_ptr<GeoAddress>> result = callback->GetResult();
233 if (!WriteResultToParcel(result, reply, true)) {
234 return ERRCODE_REVERSE_GEOCODING_FAIL;
235 }
236 return ERRCODE_SUCCESS;
237 }
238
ReportAddressMock(MessageParcel & data,MessageParcel & reply)239 void GeoConvertService::ReportAddressMock(MessageParcel &data, MessageParcel &reply)
240 {
241 int arraySize = 0;
242 std::vector<std::shared_ptr<GeoAddress>> array;
243 ReverseGeocodeRequest request;
244 request.latitude = data.ReadDouble();
245 request.longitude = data.ReadDouble();
246 request.maxItems = data.ReadInt32();
247 data.ReadInt32(); // locale size
248 request.locale = Str16ToStr8(data.ReadString16());
249 std::unique_lock<std::mutex> lock(mockInfoMutex_, std::defer_lock);
250 lock.lock();
251 for (size_t i = 0; i < mockInfo_.size(); i++) {
252 std::shared_ptr<GeocodingMockInfo> info = mockInfo_[i];
253 if (!CommonUtils::DoubleEqual(request.latitude, info->GetLocation()->latitude) ||
254 !CommonUtils::DoubleEqual(request.longitude, info->GetLocation()->longitude)) {
255 continue;
256 }
257 arraySize++;
258 array.push_back(info->GetGeoAddressInfo());
259 }
260 lock.unlock();
261 reply.WriteInt32(ERRCODE_SUCCESS);
262 if (arraySize > 0) {
263 reply.WriteInt32(arraySize);
264 for (size_t i = 0; i < array.size(); i++) {
265 array[i]->Marshalling(reply);
266 }
267 } else {
268 reply.WriteInt32(0);
269 }
270 }
271
GetAddressByLocationName(MessageParcel & data,MessageParcel & reply)272 int GeoConvertService::GetAddressByLocationName(MessageParcel &data, MessageParcel &reply)
273 {
274 if (!GetService()) {
275 reply.WriteInt32(ERRCODE_GEOCODING_FAIL);
276 return ERRCODE_GEOCODING_FAIL;
277 }
278
279 MessageParcel dataParcel;
280 MessageParcel replyParcel;
281 MessageOption option;
282
283 if (!WriteInfoToParcel(data, dataParcel, false)) {
284 reply.WriteInt32(ERRCODE_GEOCODING_FAIL);
285 return ERRCODE_GEOCODING_FAIL;
286 }
287 sptr<GeoConvertCallbackHost> callback = new (std::nothrow) GeoConvertCallbackHost();
288 if (callback == nullptr) {
289 LBSLOGE(GEO_CONVERT, "can not get valid callback.");
290 reply.WriteInt32(ERRCODE_GEOCODING_FAIL);
291 return ERRCODE_GEOCODING_FAIL;
292 }
293 dataParcel.WriteRemoteObject(callback->AsObject());
294 if (serviceProxy_ == nullptr) {
295 LBSLOGE(GEO_CONVERT, "serviceProxy is nullptr!");
296 reply.WriteInt32(ERRCODE_GEOCODING_FAIL);
297 return ERRCODE_GEOCODING_FAIL;
298 }
299 int error = serviceProxy_->SendRequest(REQUEST_GEOCODE, dataParcel, replyParcel, option);
300 if (error != ERR_OK) {
301 LBSLOGE(GEO_CONVERT, "SendRequest to cloud service failed.");
302 reply.WriteInt32(ERRCODE_GEOCODING_FAIL);
303 return ERRCODE_GEOCODING_FAIL;
304 }
305 std::list<std::shared_ptr<GeoAddress>> result = callback->GetResult();
306 if (!WriteResultToParcel(result, reply, false)) {
307 return ERRCODE_GEOCODING_FAIL;
308 }
309 return ERRCODE_SUCCESS;
310 }
311
312 /*
313 * get info from data and write to dataParcel.
314 * flag: true for reverse geocoding, false for geocoding.
315 */
WriteInfoToParcel(MessageParcel & data,MessageParcel & dataParcel,bool flag)316 bool GeoConvertService::WriteInfoToParcel(MessageParcel &data, MessageParcel &dataParcel, bool flag)
317 {
318 if (flag) {
319 dataParcel.WriteString16(data.ReadString16()); // locale
320 dataParcel.WriteDouble(data.ReadDouble()); // latitude
321 dataParcel.WriteDouble(data.ReadDouble()); // longitude
322 dataParcel.WriteInt32(data.ReadInt32()); // maxItems
323 } else {
324 dataParcel.WriteString16(data.ReadString16()); // locale
325 dataParcel.WriteString16(data.ReadString16()); // description
326 dataParcel.WriteInt32(data.ReadInt32()); // maxItems
327 dataParcel.WriteDouble(data.ReadDouble()); // minLatitude
328 dataParcel.WriteDouble(data.ReadDouble()); // minLongitude
329 dataParcel.WriteDouble(data.ReadDouble()); // maxLatitude
330 dataParcel.WriteDouble(data.ReadDouble()); // maxLongitude
331 }
332 dataParcel.WriteString16(data.ReadString16()); // bundleName
333 return true;
334 }
335
336 /*
337 * write result info to reply.
338 * flag: true for reverse geocoding, false for geocoding.
339 */
WriteResultToParcel(const std::list<std::shared_ptr<GeoAddress>> result,MessageParcel & reply,bool flag)340 bool GeoConvertService::WriteResultToParcel(const std::list<std::shared_ptr<GeoAddress>> result,
341 MessageParcel &reply, bool flag)
342 {
343 if (result.size() == 0) {
344 LBSLOGE(GEO_CONVERT, "empty result!");
345 reply.WriteInt32(flag ? ERRCODE_REVERSE_GEOCODING_FAIL : ERRCODE_GEOCODING_FAIL);
346 return false;
347 }
348 reply.WriteInt32(ERRCODE_SUCCESS);
349 reply.WriteInt32(result.size());
350 for (auto iter = result.begin(); iter != result.end(); iter++) {
351 std::shared_ptr<GeoAddress> address = *iter;
352 if (address != nullptr) {
353 address->Marshalling(reply);
354 }
355 }
356 return true;
357 }
358
GetService()359 bool GeoConvertService::GetService()
360 {
361 if (!IsConnect()) {
362 std::string serviceName;
363 bool result = LocationConfigManager::GetInstance().GetGeocodeServiceName(serviceName);
364 if (!result || serviceName.empty()) {
365 LBSLOGE(GEO_CONVERT, "get service name failed!");
366 return false;
367 }
368 if (!CommonUtils::CheckAppInstalled(serviceName)) { // app is not installed
369 LBSLOGE(GEO_CONVERT, "service is not available.");
370 return false;
371 } else if (!ReConnectService()) {
372 return false;
373 }
374 }
375 return true;
376 }
377
IsConnect()378 bool GeoConvertService::IsConnect()
379 {
380 std::unique_lock<std::mutex> uniqueLock(mutex_);
381 return serviceProxy_ != nullptr;
382 }
383
EnableReverseGeocodingMock()384 bool GeoConvertService::EnableReverseGeocodingMock()
385 {
386 LBSLOGD(GEO_CONVERT, "EnableReverseGeocodingMock");
387 mockEnabled_ = true;
388 return true;
389 }
390
DisableReverseGeocodingMock()391 bool GeoConvertService::DisableReverseGeocodingMock()
392 {
393 LBSLOGD(GEO_CONVERT, "DisableReverseGeocodingMock");
394 mockEnabled_ = false;
395 return true;
396 }
397
SetReverseGeocodingMockInfo(std::vector<std::shared_ptr<GeocodingMockInfo>> & mockInfo)398 LocationErrCode GeoConvertService::SetReverseGeocodingMockInfo(
399 std::vector<std::shared_ptr<GeocodingMockInfo>>& mockInfo)
400 {
401 LBSLOGD(GEO_CONVERT, "SetReverseGeocodingMockInfo");
402 std::unique_lock<std::mutex> lock(mockInfoMutex_, std::defer_lock);
403 lock.lock();
404 mockInfo_.assign(mockInfo.begin(), mockInfo.end());
405 lock.unlock();
406 return ERRCODE_SUCCESS;
407 }
408
UnloadGeoConvertSystemAbility()409 void GeoConvertService::UnloadGeoConvertSystemAbility()
410 {
411 auto locationSaLoadManager = DelayedSingleton<LocationSaLoadManager>::GetInstance();
412 if (!CheckIfGeoConvertConnecting() && locationSaLoadManager != nullptr) {
413 locationSaLoadManager->UnloadLocationSa(LOCATION_GEO_CONVERT_SA_ID);
414 }
415 }
416
CheckIfGeoConvertConnecting()417 bool GeoConvertService::CheckIfGeoConvertConnecting()
418 {
419 return mockEnabled_;
420 }
421
SaDumpInfo(std::string & result)422 void GeoConvertService::SaDumpInfo(std::string& result)
423 {
424 result += "GeoConvert enable status: false";
425 result += "\n";
426 }
427
Dump(int32_t fd,const std::vector<std::u16string> & args)428 int32_t GeoConvertService::Dump(int32_t fd, const std::vector<std::u16string>& args)
429 {
430 std::vector<std::string> vecArgs;
431 std::transform(args.begin(), args.end(), std::back_inserter(vecArgs), [](const std::u16string &arg) {
432 return Str16ToStr8(arg);
433 });
434
435 LocationDumper dumper;
436 std::string result;
437 dumper.GeocodeDump(SaDumpInfo, vecArgs, result);
438 if (!SaveStringToFd(fd, result)) {
439 LBSLOGE(GEO_CONVERT, "Geocode save string to fd failed!");
440 return ERR_OK;
441 }
442 return ERR_OK;
443 }
444 } // namespace Location
445 } // namespace OHOS
446 #endif
447