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