OpenHarmony开发者论坛
标题:
OpenHarmony4.0源码解析之位置服务子系统
[打印本页]
作者:
深开鸿_王奎
时间:
2024-1-5 17:42
标题:
OpenHarmony4.0源码解析之位置服务子系统
[md]OpenHarmony4.0 源码解析之位置服务子系统
作者:王奎
## 1. Location子系统简介
### 1.1 Location架构图
![location架构图.png](
https://forums-obs.openharmony.c ... jf632fncgj3nx0x.png
"location架构图.png")
### 1.2 目录结构
```shell
/base/location # 源代码目录结构:
├── figures # 存放readme中的架构图
├── frameworks # 框架代码
├── interfaces # 对外接口
├── sa_profile # SA的配置文件
├── services # 定位服务各个SA代码目录
├── test # 测试代码目录
```
### 1.3 约束
- 使用设备的位置能力,需要用户进行确认并主动开启位置开关。如果位置开关没有开启,系统不会向任何应用提供位置服务。
- 设备位置信息属于用户敏感数据,所以即使用户已经开启位置开关,应用在获取设备位置前仍需向用户申请位置访问权限。在用户确认允许后,系统才会向应用提供位置服务。即在JS应用中请求位置权限
## 2.流程梳理
### 2.1 IDL接口
- ILocator: 提供Locator服务对外SDK接口,包含订阅/停止订阅、回调注册、位置上报等;
- ILocatorCallback: 提供位置信息、定位状态(启动/停止)、异常状态回调接口;
- IGeoConvert: 提供地理编码服务相关接口
- IGnssAbility: 提供GNSS服务相关接口
- INetWorkAbility: 提供网络定位服务接口
- IPassiveAbility: 提供被动定位服务接口
- IGnssCallback: 提供驱动框架(GNSS HDI)位置信息回调接口
- IAGnssCallback:提供驱动框架(GNSS HDI)辅助定位信息回调接口
#### 2.1.1 请求参数RequestConfig
RequestConfig参数说明:
- scenario:表示场景信息,取值范围如下,用于设置定位方式
```c++
enum {
SCENE_UNSET = 0x0300,
SCENE_NAVIGATION = 0x0301,//该场景采用GPS定位
SCENE_TRAJECTORY_TRACKING = 0x0302,///该场景采用GPS定位
SCENE_CAR_HAILING = 0x0303,//该场景采用GPS定位
SCENE_DAILY_LIFE_SERVICE = 0x0304,//该场景采用network定位
SCENE_NO_POWER = 0x0305//该场景采用passive定位
}
```
- timeInterval:表示上报位置信息的时间间隔,单位是秒。默认值为1,取值范围为大于等于0。
- maxAccuracy:表示精度信息,单位是米。仅在精确位置功能场景下有效,模糊位置功能生效场景下该字段无意义。默认值为0,取值范围为大于等于0。
- fixNumber:上报次数;0-不限次数,1-N: 仅上报一次
- distanceInterval:表示上报位置信息的距离间隔。单位是米,默认值为0,取值范围为大于等于0。
- timeOut:表示获取定位数据的超时时长,默认为30s。
- priority:用于设置优先级&定位方式,取值范围如下
```c++
enum {
PRIORITY_UNSET = 0x0200,
PRIORITY_ACCURACY = 0x0201,//采用GPS定位
PRIORITY_LOW_POWER = 0x0202,//采用passive定位
PRIORITY_FAST_FIRST_FIX = 0x0203//采用gnss network同时定位
};
```
#### 2.1.2 部分接口说明
- LocatorAbility: ILocator接口类的服务端实现,位置服务核心单例类,负责维护定位请求及回调对象列表;同时也负责拉起ReportManager将数据发送给JS层
- RequestManager: 定位请求管理类
- ReportManager: 定位信息上报管理类;
### 2.2 locationhub服务端启动
Location子系统涉及到多个服务,而这些服务在sa_profile中通过xml文件进行注册。在系统上电后,sa_main读取/system/profile/locationhub.xml动态加载lbsservice_locator、lbsservice_gnss、lbsservice_network、lbsservice_passive以及lbsservice_geocode,启动位置服务进程locationhub。
1)通过GeoConvertService::OnStart向samgr注册ID为2801的sa服务;
2)通过LocatorAbility::OnStart向samgr注册ID为2802的sa服务;
3)通过GnssAbility::OnStart向samgr注册ID为2803的sa服务;
4)通过NetworkAbility::OnStart向samgr注册ID为sa为2804的sa服务;
5)通过PassiveAbility::OnStart向samgr注册ID为2805的sa服务;
初始化的时候各个服务通过OnStart函数进行初始化。
### 2.3 开启位置订阅流程
![location.jpg](
https://forums-obs.openharmony.c ... y1qc1c1efyffqzw.jpg
"location.jpg")
![location2.jpg](
https://forums-obs.openharmony.c ... fwi8oro8z22wule.jpg
"location2.jpg")
流程说明:
1. 订阅者调用Locator接口类StartLocating启动定位,Client侧会调用LocatorProxy,经过RPC通信流程,将LocatorInterfaceCode::START_LOCATING消息发送至locationhub服务侧
2. locationhub服务侧的LocatorAbilityStub接收到LocatorProxy发送的消息后,调用CheckLocationSwitchState检查位置服务的开关是否打开,并通过CheckLocationPermission进行权限校验。校验通过后,对Client侧注册至服务侧的callback添加死亡监听,生成callback的proxy代理,随后调用LocatorAbility::StartLocating。
3. LocatorAbility收到函数调用指令后,再次调用QuerySwitchState检查位置服务开关是否打开,并调用CheckSaValid检查各定位模式的SA服务是否被成功拉起,如若服务未被拉起,则执行UpdateProxyMap开启定位
4. 创建新Request,将用户下发的requestConfig以及Client侧的信息记录其中。调用RequestManager::HandleStartLocating处理定位请求:
- 调用RestorRequest,将定位请求Request插入LocatorAbility服务维护的请求列表receivers_中。
- 调用UpdateRequestRecord,依据用户下发的requestConfig.scenario(场景信息),获取定位模式,并更新各定位模式的请求列表。
- 调用HandleRequest处理各定位模式的请求列表,将Request封装成WorkRecord,在ProxySendLocationRequest函数中调用SendLocationRequest唤醒服务代理,发送SEND_LOCATION_REQUEST消息码通知对应的SA处理请求。**(以下以GnssAbility为例)**
5. 在对应的SA服务内,ServiceStub接收到Proxy发送的SEND_LOCATION_REQUEST消息码,调用SendMessage处理请求
6. 调用GnssHandler::SendEvent,将SEND_LOCATION_REQUEST消息事件进行转发,并在GnssHandler:
rocessEvent中接收消息并进行处理。
7. 调用SubAbility:
ocationRequest处理WorkRecord请求。
- 在GnssAbility服务中更新newRecord_请求队列,调用HandleRefrashRequirements处理定位请求
- 调用HandleLocalRequest,随即调用HandleRemoveRecord处理新的newRecord定位请求。在HandleRemoveRecord函数内,会将新的newRecord与lastRecord\_内的请求进行比对,如果新的请求newRecord在lastRecord\_中不存在,则调用RequestRecord移除lastRecord\_内的请求。
- 调用StopGnss,停止定位
- 检查SA服务维护的新请求列表是否为空,如果请求列表为空,则调用RemoveHdi与驱动层断开连接
- 调用HandleAddRecord,将新的newRecord与已有的请求队列lastRecord\_内的请求进行比对,如果新的请求newRecord在lastRecord\_中未注册,则调用RequestRecord处理新请求
- 调用ConnectHdi,获取IGnssInterface以及IAGnssInterface类实例,连接HDI层,并初始化回调类GnssEventCallback与AGnssEventCallback的实例。
- 调用EnableGnss,在函数内调用IGnssInterface::EnableGnss将GnssEventCallback回调实例注册到底层。
- 调用SetAgnssCallback,在函数内调用IGnssInterface::SetAgnssCallback将IAGnssCallback回调实例注册到底层。
- 调用SetAgnssServer,设置AgnssServer的参数
- 调用StartGnss,开启定位。
- 在HandleLocalRequest结束HandleLocalRequest调用后,刷新lastRecord\_,将刚才处理完的定位请求newRecord\_插入lastRecord_
### 2.4 定位上报流程
![locationcallback.jpg](
https://forums-obs.openharmony.c ... wvhjvvf7ujmzhjr.jpg
"locationcallback.jpg")
流程说明:
1. Gnss模块获取数据,驱动层调用注册的GnssEventCallback->ReportLocation开始上报数据。在ReportLocation中,将LocationInfo重新封装为Location数据。
2. 调用ReportLocationInfo继续进行数据上报,通过IPC机制将Location数据以及REPORT_LOCATION消息码转发至Locator服务端
3. 在Locator服务端,调用PreReportLocation,完成数据解析后,调用ReportLocation处理数据上报流程
4. 调用OnReportLocation,更新lastLocation_数据并校验定位模式的请求列表是否为空,遍历request列表,处理request请求
5. 调用ProcessRequestForReport,获取注册在request内的LocatorCallbackProxy代理,调用OnLocationReport上报Location数据
6. 经过IPC通信流程,在proxy内将RECEIVE_LOCATION_INFO_EVENT消息码转发至LocatorCallbackHost服务端
7. 调用OnLocationReport,初始化异步工作队列环境
8. 调用DoSendWork,在其中调用uv_queue_work,添加异步任务到libuv的工作线程池中,将定位数据上报至应用层
## 3.源码分析
### 3.1 位置订阅流程
以 geolocation.on('locationChange')为例
1. 订阅者调用Locator接口类StartLocating启动定位,Client侧会调用LocatorProxy,经过RPC通信流程,将LocatorInterfaceCode::START_LOCATING消息发送至locationhub服务侧,LocatorAbilityStub接收到LocatorProxy发送的消息后,调用CheckLocationSwitchState检查位置服务的开关是否打开,并通过CheckLocationPermission进行权限校验。校验无误后注册callback的死亡回调,并生成callback的proxy代理,随后调用LocatorAbility::StartLocating转发定位请求。
```c++
void LocatorImpl::StartLocating(std::unique_ptr<RequestConfig>& requestConfig,
sptr<ILocatorCallback>& callback)
{
......
client_->StartLocating(requestConfig, callback, "location.ILocator", 0, 0);
}
```
```c++
int LocatorProxy::StartLocating(std::unique_ptr<RequestConfig>& requestConfig,
sptr<ILocatorCallback>& callback, std::string bundleName, pid_t pid, pid_t uid)
{
...
//向locationhub服务端发送START_LOCATING消息码
int error = remote->SendRequest(START_LOCATING, data, reply, option);
LBSLOGD(LOCATOR_STANDARD, "
roxy::StartLocating Transact ErrCodes = %{public}d", error);
return error;
}
```
```c++
int32_t LocatorAbilityStub::OnRemoteRequest(uint32_t code,
MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
......
//code = LocatorInterfaceCode::START_LOCATING
auto handleFunc = locatorHandleMap_.find(code);
if (handleFunc != locatorHandleMap_.end() && handleFunc->second != nullptr) {
auto memberFunc = handleFunc->second;
ret = (this->*memberFunc)(data, reply, identity);
}
......
}
```
```c++
int LocatorAbilityStub:
reStartLocating(MessageParcel &data, MessageParcel &reply, AppIdentity &identity)
{
//校验定位开关
if (!CheckLocationSwitchState(reply)) {
return ERRCODE_SWITCH_OFF;
}
//权限校验
if (!CheckLocationPermission(reply, identity)) {
return ERRCODE_PERMISSION_DENIED;
}
......
//注册callback的死亡监听
sptr<IRemoteObject:
eathRecipient> death(new (std::nothrow) LocatorCallbackDeathRecipient());
remoteObject->AddDeathRecipient(death);
//生成callback的proxy代理
sptr<ILocatorCallback> callback = iface_cast<ILocatorCallback>(remoteObject);
//开启定位
reply.WriteInt32(locatorAbility->StartLocating(requestConfig, callback, identity));
......
}
```
2. LocatorAbility服务内,调用QuerySwitchState检查位置服务开关是否打开,并调用CheckSaValid检查各定位模式的的SA服务是否被成功拉起,如若服务未被拉起,则执行UpdateProxyMap开启定位。反之则创建新Request,将用户下发的requestConfig以及Client侧的信息封装其中,调用RequestManager::HandleStartLocating处理定位请求。
```c++
LocationErrCode LocatorAbility::StartLocating(std::unique_ptr<RequestConfig>& requestConfig,
sptr<ILocatorCallback>& callback, AppIdentity &identity)
{
//检查位置开关
if (QuerySwitchState() == DISABLED) {
ReportErrorStatus(callback, ERROR_SWITCH_UNOPEN);
}
//检查gps,network和passive服务是否可用
if (!CheckSaValid()) {
UpdateSaAbilityHandler();
}
......
reportManager_->UpdateRandom();
// 生成请求request实例
std::shared_ptr<Request> request = std::make_shared<Request>();
request->SetUid(identity.GetUid());
request->SetPid(identity.GetPid());
request->SetTokenId(identity.GetTokenId());
request->SetFirstTokenId(identity.GetFirstTokenId());
request->SetPackageName(identity.GetBundleName());
request->SetRequestConfig(*requestConfig);
request->SetLocatorCallBack(callback);
request->SetUuid(std::to_string(CommonUtils::IntRandom(MIN_INT_RANDOM, MAX_INT_RANDOM)));
......
//处理定位请求
requestManager_->HandleStartLocating(request);//renew requests
//上报SESSION_START状态事件
ReportLocationStatus(callback, SESSION_START);
......
}
```
```c++
void RequestManager::HandleStartLocating(std::shared_ptr<Request> request)
{
auto locatorAbility = DelayedSingleton<LocatorAbility>::GetInstance();
auto locatorDftManager = DelayedSingleton<LocatorDftManager>::GetInstance();
if (locatorAbility == nullptr || locatorDftManager == nullptr) {
return;
}
// 刷新请求列表
bool isNewRequest = RestorRequest(request);
if (isNewRequest) {
locatorAbility->RegisterPermissionCallback(request->GetTokenId(),
{ACCESS_APPROXIMATELY_LOCATION, ACCESS_LOCATION, ACCESS_BACKGROUND_LOCATION});
//将新的请求插入requests_队列
UpdateRequestRecord(request, true);//insert new request into requests_
UpdateUsingPermission(request);
locatorDftManager->LocationSessionStart(request);
}
// 处理定位请求
HandleRequest();
}
```
3. 处理定位请求:
调用RestorRequest,将定位请求Request插入LocatorAbility服务维护的请求列表receivers_中。
```c++
bool RequestManager::RestorRequest(std::shared_ptr<Request> newRequest)
{
......
//如果最新的定位请求的Requestcallabck以及Requestconfig都与列表汇总已有的请求相同,则不将该请求插入列表
auto iterator = receivers->find(newCallback);
if (iterator == receivers->end()) {
std::list<std::shared_ptr<Request>> requestList;
requestList.push_back(newRequest);
receivers->insert(make_pair(newCallback, requestList));
LBSLOGD(REQUEST_MANAGER, "add new receiver with new callback");
return true;
}
sptr<RequestConfig> newConfig = newRequest->GetRequestConfig();
std::list<std::shared_ptr<Request>> requestWithSameCallback = iterator->second;
for (auto iter = requestWithSameCallback.begin(); iter != requestWithSameCallback.end(); ++iter) {
auto request = *iter;
......
auto requestConfig = request->GetRequestConfig();
......
//如果新请求的RequestConfig中的场景信息(scenario)、优先级(priority)与请求列表中已有项相同,则更新RequestConfig。
if (newConfig->IsSame(*requestConfig)) {
request->SetRequestConfig(*newConfig);
......
return false;
}
}
......
}
```
调用UpdateRequestRecord,依据用户下发的requestConfig.scenario,获取定位模式,并将新的request插入LocatorAbility服务维护的requests_集合与定位模式相关联的列表中。
```c++
void RequestManager::UpdateRequestRecord(std::shared_ptr<Request> request, bool shouldInsert)
{
......
//获取定位模式
request->GetProxyName(proxys);
......
for (std::list<std::string>::iterator iter = proxys->begin(); iter != proxys->end(); ++iter) {
......
//更新各定位模式的请求列表
UpdateRequestRecord(request, abilityName, shouldInsert);
}
}
```
调用RequestManager::HandleRequest处理各定位模式的请求列表,将定位请求交由定位模式服务代理转发。
```c++
void RequestManager::HandleRequest()
{
...
std::map<std::string, sptr<IRemoteObject>>::iterator iter;
for (iter = proxyMap->begin(); iter != proxyMap->end(); ++iter) {
std::string abilityName = iter->first;
//处理请求
HandleRequest(abilityName);
}
}
```
```c++
void RequestManager::HandleRequest(std::string abilityName)
{
...
ProxySendLocationRequest(abilityName, *workRecord, timeInterval);
}
```
```c++
void RequestManager:
roxySendLocationRequest(std::string abilityName, WorkRecord& workRecord, int timeInterval)
{
...
if (abilityName == GNSS_ABILITY) {
//唤醒代理转发定位请求
std::unique_ptr<GnssAbilityProxy> gnssProxy = std::make_unique<GnssAbilityProxy>(remoteObject);
gnssProxy->SendLocationRequest(timeInterval, workRecord);
}
......
}
```
调用GnssAbilityProxy::SendLocationRequest发送SEND_LOCATION_REQUEST消息码通知对应的SA处理请求
```c++
void GnssAbilityProxy::SendLocationRequest(uint64_t interval, WorkRecord &workrecord)
{
...
//发送SEND_LOCATION_REQUEST消息码通知对应的SA处理请求
int error = Remote()->SendRequest(ISubAbility::SEND_LOCATION_REQUEST, data, reply, option);
...
}
```
4. ServiceStub接收到Proxy发送的SEND_LOCATION_REQUEST消息码,调用SendMessage处理请求
```c++
int GnssAbilityStub::OnRemoteRequest(uint32_t code,MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
...
int ret = REPLY_NO_EXCEPTION;
switch (code) {
case SEND_LOCATION_REQUEST: {
......
//调用SendMessage处理请求
SendMessage(code, data, reply);
......
}
...
}
return ret;
}
```
5. 调用GnssHandler::SendEvent,将SEND_LOCATION_REQUEST消息事件进行转发,并在GnssHandler:
rocessEvent中接收消息并进行处理
```c++
void GnssAbility::SendMessage(uint32_t code, MessageParcel &data, MessageParcel &reply)
{
......
switch (code) {
//code = SEND_LOCATION_REQUEST
case static_cast<uint32_t>(GnssInterfaceCode::SEND_LOCATION_REQUEST): {
......
//调用GnssHandler::SendEvent,将SEND_LOCATION_REQUEST消息事件进行转发
if (gnssHandler_->SendEvent(event)) {
reply.WriteInt32(ERRCODE_SUCCESS);
}
......
}
......
}
}
```
```c++
void GnssHandler:
rocessEvent(const AppExecFwk::InnerEvent:
ointer& event)
{
......
switch (eventId) {
......
case static_cast<uint32_t>(GnssInterfaceCode::SEND_LOCATION_REQUEST): {
std::unique_ptr<WorkRecord> workrecord = event->GetUniqueObject<WorkRecord>();
if (workrecord != nullptr) {
//处理定位请求
gnssAbility->LocationRequest(*workrecord);
}
break;
}
......
}
......
}
```
6. 调用SubAbility:
ocationRequest处理WorkRecord请求,更新定位请求参数,随即调用HandleRemoveRecord处理新的newRecord定位请求。
```c++
void SubAbility:
ocationRequest(WorkRecord &workRecord)
{
interval_ = workRecord.GetTimeInterval(0);
//更新最新定位请求的参数
newRecord_->Clear();
newRecord_->Set(workRecord);
//调用HandleRefrashRequirements处理请求
HandleRefrashRequirements();
}
```
```c++
void SubAbility::HandleRefrashRequirements()
{
......
// send local request
HandleLocalRequest(*newRecord_);
lastRecord_->Clear();
lastRecord_->Set(*newRecord_);
}
```
在HandleRemoveRecord函数内,处理请求。
```c++
void SubAbility::HandleLocalRequest(WorkRecord &record)
{
HandleRemoveRecord(record);
HandleAddRecord(record);
}
```
- 调用HandleRemoveRecord,对已处理完成的请求取消订阅
```c++
void SubAbility::HandleRemoveRecord(WorkRecord &newRecord)
{
for (int i = 0; i < lastRecord_->Size(); i++) {
int uid = lastRecord_->GetUid(i);
bool isFind = newRecord.Find(uid, lastRecord_->GetName(i), lastRecord_->GetUuid(i));
......
//将新的newRecord与lastRecord_内的请求进行比对,如果新的请求newRecord在lastRecord_中不存在,则调用RequestRecord移除 lastRecord_内的请求。
if (!isFind) {
......
RequestRecord(*workRecord, false);
}
}
}
```
- 调用HandleAddRecord,处理新的定位请求
```c++
void SubAbility::HandleAddRecord(WorkRecord &newRecord)
{
for (int i = 0; i < newRecord.Size(); i++) {
......
//将新的newRecord与已有的请求队列lastRecord\_内的请求进行比对,如果新的请求newRecord在lastRecord\_中不存在,则调用RequestRecord 处理新请求
bool isFind = lastRecord_->Find(uid, newRecord.GetName(i), lastRecord_->GetUuid(i));
......
if (!isFind) {
......
workRecord->Add(uid, newRecord.GetPid(i), newRecord.GetName(i),
newRecord.GetTimeInterval(i), newRecord.GetUuid(i));
......
RequestRecord(*workRecord, true);
}
}
}
```
7. 调用RequestRecord处理新请求----HandleAddRecord与HandleRemoveRecord都会调用此函数,但走的流程不同
- 在HandleAddRecord调用流程中,会连接Hdi,初始化回调函数实例,注册回调,开启定位
```c++
void GnssAbility::RequestRecord(WorkRecord &workRecord, bool isAdded)
{
......
if (isAdded) {
if (!isHdiConnected_) {
ConnectHdi();
EnableGnss();
SetAgnssCallback();
SetAgnssServer();
isHdiConnected_ = true;
}
StartGnss();
} else {
......
}
......
}
```
连接Hdi层,初始化回调函数实例
```c++
bool GnssAbility::ConnectHdi()
{
......
int32_t retry = 0;
while (retry < GET_HDI_SERVICE_COUNT) {
......
gnssInterface_ = IGnssInterface::Get();
agnssInterface_ = IAGnssInterface::Get();
if (gnssInterface_ != nullptr && agnssInterface_ != nullptr) {
......
//GNSS与AGNSS回调实例化
gnssCallback_ = new (std::nothrow) GnssEventCallback();
agnssCallback_ = new (std::nothrow) AGnssEventCallback();
......
return true;
}
......
}
......
}
```
使能Gnss,注册Gnss回调
```c++
bool GnssAbility::EnableGnss()
{
......
//
int32_t ret = gnssInterface_->EnableGnss(gnssCallback_);
......
}
```
注册Agnss回调至驱动层
```c++
void GnssAbility::SetAgnssCallback()
{
......
agnssInterface_->SetAgnssCallback(agnssCallback_);
}
```
下发AgnssServer配置参数
```c++
void GnssAbility::SetAgnssServer()
{
......
AGnssServerInfo info;
info.type = AGNSS_TYPE_SUPL;
info.server = AGNSS_SERVER_ADDR;
info.port = AGNSS_SERVER_PORT;
agnssInterface_->SetAgnssServer(info);
}
```
开启定位
```c++
void GnssAbility::StartGnss()
{
......
//开启定位
int ret = gnssInterface_->StartGnss(GNSS_START_TYPE_NORMAL);
......
}
```
- 在HandleRemoveRecord调用流程中,会停止定位,断开Hdi层
```c++
void GnssAbility::RequestRecord(WorkRecord &workRecord, bool isAdded)
{
......
if (isAdded) {
......
} else {
if (isHdiConnected_) {
//停止定位
StopGnss();
if (GetRequestNum() == 0) {
//断开Hdi
RemoveHdi();
isHdiConnected_ = false;
}
}
}
......
}
```
停止定位
```c++
void GnssAbility::StopGnss()
{
if (gnssInterface_ == nullptr) {
LBSLOGE(GNSS, "gnssInterface_ is nullptr");
return;
}
if (!IsGnssEnabled()) {
LBSLOGE(GNSS, "gnss has been disabled");
return;
}
if (GetRequestNum() != 0) {
return;
}
int ret = gnssInterface_->StopGnss(GNSS_START_TYPE_NORMAL);
if (ret == 0) {
gnssWorkingStatus_ = GNSS_STATUS_SESSION_END;
}
}
```
断开Hdi
```c++
bool GnssAbility::RemoveHdi()
{
auto devmgr = HDI:
eviceManager::V1_0::IDeviceManager::Get();
......
if (devmgr->UnloadDevice(GNSS_SERVICE_NAME) != 0) {
LBSLOGE(GNSS, "Load gnss service failed!");
return false;
}
if (devmgr->UnloadDevice(AGNSS_SERVICE_NAME) != 0) {
LBSLOGE(GNSS, "Load agnss service failed!");
return false;
}
return true;
}
```
### 3.2 定位上报流程
1. GNSS模组获取定位数据,驱动层调用注册的GnssEventCallback回调类的ReportLocation上报数据
```c++
int32_t GnssEventCallback::ReportLocation(const LocationInfo& location)
{
......
//将GNSS数据封装为Location实例
std::string identity = IPCSkeleton::ResetCallingIdentity();
std::shared_ptr<Location> locationNew = std::make_shared<Location>();
locationNew->SetLatitude(location.latitude);
locationNew->SetLongitude(location.longitude);
locationNew->SetAltitude(location.altitude);
locationNew->SetAccuracy(location.accuracy);
locationNew->SetSpeed(location.speed);
locationNew->SetDirection(location.direction);
locationNew->SetTimeStamp(location.timeStamp);
locationNew->SetTimeSinceBoot(location.timeSinceBoot);
locationNew->SetIsFromMock(false);
......
//调用ReportLocationInfo上报数据
gnssAbility->ReportLocationInfo(GNSS_ABILITY, locationNew);
......
}
```
2. 调用SubAbility::ReportLocationInfo,向Locator服务端上报数据
```c++
void SubAbility::ReportLocationInfo(
const std::string& systemAbility, const std::shared_ptr<Location> location)
{
......
sptr<IRemoteObject> objectLocator =
CommonUtils::GetRemoteObject(LOCATION_LOCATOR_SA_ID, CommonUtils::InitDeviceId());
......
//向Locator服务端上报数据
objectLocator->SendRequest(static_cast<int>(LocatorInterfaceCode::REPORT_LOCATION), data, reply, option);
}
```
```c++
locatorHandleMap_[static_cast<int>(LocatorInterfaceCode::REPORT_LOCATION)] =
&LocatorAbilityStub:
reReportLocation;
int32_t LocatorAbilityStub::OnRemoteRequest(uint32_t code,
MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
......
//code = REPORT_LOCATION
auto handleFunc = locatorHandleMap_.find(code);
if (handleFunc != locatorHandleMap_.end() && handleFunc->second != nullptr) {
auto memberFunc = handleFunc->second;
ret = (this->*memberFunc)(data, reply, identity);
} else {
......
}
......
}
```
3. Locator服务端调用PreReportLocation处理数据上报
```c++
int LocatorAbilityStub:
reReportLocation(MessageParcel &data, MessageParcel &reply, AppIdentity &identity)
{
......
locatorAbility->ReportLocation(location, systemAbility);
......
}
```
LocatorAbility执行ReportLocation上报定位数据
``````c++
bool ReportManager::OnReportLocation(const std::unique_ptr<Location>& location, std::string abilityName)
{
......
auto requestMap = locatorAbility->GetRequests();
......
auto requestList = requestListIter->second;
auto deadRequests = std::make_unique<std::list<std::shared_ptr<Request>>>();
for (auto iter = requestList.begin(); iter != requestList.end(); iter++) {
auto request = *iter;
if (!ProcessRequestForReport(request, deadRequests, location)) {
continue;
}
}
......
}
``````
```c++
bool ReportManager:
rocessRequestForReport(std::shared_ptr<Request>& request,
std::unique_ptr<std::list<std::shared_ptr<Request>>>& deadRequests, const std::unique_ptr<Location>& location)
{
......
request->SetLastLocation(finalLocation);
auto locatorCallback = request->GetLocatorCallBack();
if (locatorCallback != nullptr) {
//调用注册在request的回调类上报定位数据
locatorCallback->OnLocationReport(finalLocation);
}
......
}
```
4. 调用注册在request的回调类上报定位数据
```c++
void LocatorCallbackProxy::OnLocationReport(const std::unique_ptr<Location>& location)
{
......
int error = Remote()->SendRequest(ILocatorCallback::RECEIVE_LOCATION_INFO_EVENT, data, reply, option);
......
}
```
```c++
int LocatorCallbackHost::OnRemoteRequest(uint32_t code,
MessageParcel& data, MessageParcel& reply, MessageOption& option)
{
//code = RECEIVE_LOCATION_INFO_EVENT
switch (code) {
case RECEIVE_LOCATION_INFO_EVENT: {
......
//调用OnLocationReport
OnLocationReport(location);
std::shared_lock<std::shared_mutex> guard(mutex_);
singleLocation_ = std::move(location);
CountDown();
break;
}
......
}
}
```
5. 调用用户注册的callback回调上报定位数据
```c++
void LocatorCallbackHost::OnLocationReport(const std::unique_ptr<Location>& location)
{
std::shared_lock<std::shared_mutex> guard(mutex_);
uv_loop_s *loop = nullptr;
if (env_ == nullptr) {
LBSLOGE(LOCATOR_CALLBACK, "env_ is nullptr.");
return;
}
NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
if (loop == nullptr) {
LBSLOGE(LOCATOR_CALLBACK, "loop == nullptr.");
return;
}
uv_work_t *work = new (std::nothrow) uv_work_t;
if (work == nullptr) {
LBSLOGE(LOCATOR_CALLBACK, "work == nullptr.");
return;
}
auto context = new (std::nothrow) LocationAsyncContext(env_);
if (context == nullptr) {
LBSLOGE(LOCATOR_CALLBACK, "context == nullptr.");
delete work;
return;
}
if (!InitContext(context)) {
LBSLOGE(LOCATOR_CALLBACK, "InitContext fail");
}
context->loc = std::make_unique<Location>(*location);
work->data = context;
DoSendWork(loop, work);
}
```
```c++
void LocatorCallbackHost:
oSendWork(uv_loop_s*& loop, uv_work_t*& work)
{
uv_queue_work(loop, work, [](uv_work_t* work) {}, [](uv_work_t* work, int status) {
if (work == nullptr) {
return;
}
napi_handle_scope scope = nullptr;
auto context = static_cast<LocationAsyncContext*>(work->data);
if (context == nullptr) {
delete work;
return;
}
if (context->env == nullptr || context->loc == nullptr) {
delete context;
delete work;
return;
}
napi_open_handle_scope(context->env, &scope);
if (scope == nullptr) {
DELETE_SCOPE_CONTEXT_WORK(context->env, scope, context, work);
return;
}
napi_value jsEvent = nullptr;
CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent), scope, context, work);
if (context->callback[1]) {
SystemLocationToJs(context->env, context->loc, jsEvent);
} else {
LocationToJs(context->env, context->loc, jsEvent);
}
if (context->callback[0] != nullptr) {
napi_value undefine = nullptr;
napi_value handler = nullptr;
CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
scope, context, work);
CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
napi_get_reference_value(context->env, context->callback[0], &handler), scope, context, work);
if (napi_call_function(context->env, nullptr, handler, 1, &jsEvent, &undefine) != napi_ok) {
LBSLOGE(LOCATOR_CALLBACK, "Report location failed");
}
} else if (context->deferred != nullptr) {
CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
((jsEvent != nullptr) ? napi_resolve_deferred(context->env, context->deferred, jsEvent) :
napi_reject_deferred(context->env, context->deferred, jsEvent)),
scope, context, work);
}
DELETE_SCOPE_CONTEXT_WORK(context->env, scope, context, work);
});
}
```
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5