[经验分享] OpenHarmony4.0源码解析之位置服务子系统 原创 精华

深开鸿_王奎 显示全部楼层 发表于 2024-1-5 17:42:26

OpenHarmony4.0 源码解析之位置服务子系统

作者:王奎

1. Location子系统简介

1.1 Location架构图

location架构图.png

1.2 目录结构

/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:表示场景信息,取值范围如下,用于设置定位方式
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:用于设置优先级&定位方式,取值范围如下
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

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::ProcessEvent中接收消息并进行处理。
  7. 调用SubAbility::LocationRequest处理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

流程说明:

  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转发定位请求。

    void LocatorImpl::StartLocating(std::unique_ptr<RequestConfig>& requestConfig,
        sptr<ILocatorCallback>& callback)
    {
        ......
        client_->StartLocating(requestConfig, callback, "location.ILocator", 0, 0);
    }
    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, "Proxy::StartLocating Transact ErrCodes = %{public}d", error);
        return error;
    }
    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);
        } 
        ......
    }
    int LocatorAbilityStub::PreStartLocating(MessageParcel &data, MessageParcel &reply, AppIdentity &identity)
    {
        //校验定位开关
        if (!CheckLocationSwitchState(reply)) {
            return ERRCODE_SWITCH_OFF;
        }
        //权限校验
        if (!CheckLocationPermission(reply, identity)) {
            return ERRCODE_PERMISSION_DENIED;
        }
        ......
        //注册callback的死亡监听
        sptr<IRemoteObject::DeathRecipient> 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处理定位请求。

    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);
        ......
    }
    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_中。

    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_集合与定位模式相关联的列表中。

    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处理各定位模式的请求列表,将定位请求交由定位模式服务代理转发。

    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);
        }
    }
    void RequestManager::HandleRequest(std::string abilityName)
    {
        ...
        ProxySendLocationRequest(abilityName, *workRecord, timeInterval);
    }
    void RequestManager::ProxySendLocationRequest(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处理请求

    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处理请求

    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::ProcessEvent中接收消息并进行处理

    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);
                } 
                ......
            }
            ......
        }
    }
    void GnssHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer& 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::LocationRequest处理WorkRecord请求,更新定位请求参数,随即调用HandleRemoveRecord处理新的newRecord定位请求。

    void SubAbility::LocationRequest(WorkRecord &workRecord)
    {
        interval_ = workRecord.GetTimeInterval(0);
        //更新最新定位请求的参数
        newRecord_->Clear();
        newRecord_->Set(workRecord);
        //调用HandleRefrashRequirements处理请求
        HandleRefrashRequirements();
    }
    void SubAbility::HandleRefrashRequirements()
    {
         ......
        // send local request
        HandleLocalRequest(*newRecord_);
        lastRecord_->Clear();
        lastRecord_->Set(*newRecord_);
    }

    在HandleRemoveRecord函数内,处理请求。

    void SubAbility::HandleLocalRequest(WorkRecord &record)
    {
        HandleRemoveRecord(record);
        HandleAddRecord(record);
    }
    • 调用HandleRemoveRecord,对已处理完成的请求取消订阅

      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,处理新的定位请求

      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,初始化回调函数实例,注册回调,开启定位

      void GnssAbility::RequestRecord(WorkRecord &workRecord, bool isAdded)
      {
          ......
          if (isAdded) {
              if (!isHdiConnected_) {
                  ConnectHdi();
                  EnableGnss();
                  SetAgnssCallback();
                  SetAgnssServer();
                  isHdiConnected_ = true;
              }
              StartGnss();
          } else {
              ......
          }
          ......
      }

      连接Hdi层,初始化回调函数实例

      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回调

      bool GnssAbility::EnableGnss()
      {
          ......
          //
          int32_t ret = gnssInterface_->EnableGnss(gnssCallback_);
          ......
      }

      注册Agnss回调至驱动层

      void GnssAbility::SetAgnssCallback()
      {
          ......
          agnssInterface_->SetAgnssCallback(agnssCallback_);
      }

      下发AgnssServer配置参数

      void GnssAbility::SetAgnssServer()
      {
          ......
          AGnssServerInfo info;
          info.type = AGNSS_TYPE_SUPL;
          info.server = AGNSS_SERVER_ADDR;
          info.port = AGNSS_SERVER_PORT;
          agnssInterface_->SetAgnssServer(info);
      }

      开启定位

      void GnssAbility::StartGnss()
      {
          ......
          //开启定位
          int ret = gnssInterface_->StartGnss(GNSS_START_TYPE_NORMAL);
          ......
      }
    • 在HandleRemoveRecord调用流程中,会停止定位,断开Hdi层

      void GnssAbility::RequestRecord(WorkRecord &workRecord, bool isAdded)
      {
          ......
          if (isAdded) {
             ......
          } else {
              if (isHdiConnected_) {
                  //停止定位
                  StopGnss();
                  if (GetRequestNum() == 0) {
                      //断开Hdi
                      RemoveHdi();
                      isHdiConnected_ = false;
                  }
              }
          }
          ......
      }

      停止定位

      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

      bool GnssAbility::RemoveHdi()
      {
          auto devmgr = HDI::DeviceManager::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上报数据

    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服务端上报数据

    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);
    }
    locatorHandleMap_[static_cast<int>(LocatorInterfaceCode::REPORT_LOCATION)] =
            &LocatorAbilityStub::PreReportLocation;
    
    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处理数据上报

    int LocatorAbilityStub::PreReportLocation(MessageParcel &data, MessageParcel &reply, AppIdentity &identity)
    {
        ......
        locatorAbility->ReportLocation(location, systemAbility);
        ......
    }

    LocatorAbility执行ReportLocation上报定位数据

    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;
            }
        }
        ......
    }
    bool ReportManager::ProcessRequestForReport(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的回调类上报定位数据

    void LocatorCallbackProxy::OnLocationReport(const std::unique_ptr<Location>& location)
    {
        ......
        int error = Remote()->SendRequest(ILocatorCallback::RECEIVE_LOCATION_INFO_EVENT, data, reply, option);
        ......
    }
    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回调上报定位数据

    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);
    }
    void LocatorCallbackHost::DoSendWork(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);
        });
    }

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部