在前面解决问题的过程中,对GNSS模块有了更深的理解,现将心得整理如下,主要聚焦于开发者需要进行适配的adapter层是如何与上层hdi及底层闭源库进行交互的。分别通过上层系统对GPS硬件的使能以及底层GPS硬件状态变化是如何上报的来举例说明。

一、使能GPS硬件

  • 上层服务调用hdi接口使能定位

//base/location/services/location_gnss/gnss/source/gnss_ability.cpp
bool GnssAbility::EnableGnss()
{
    if (LocationDataRdbManager::QuerySwitchState() != ENABLED) {
        LBSLOGE(GNSS, "QuerySwitchState is DISABLED");
        return false;
    }
    sptr<IGnssInterface> gnssInterface = IGnssInterface::Get();
    if (gnssInterface == nullptr) {
        LBSLOGE(GNSS, "gnssInterface is nullptr");
        return false;
    }
    if (IsGnssEnabled()) {
        LBSLOGE(GNSS, "gnss has been enabled");
        return false;
    }
    std::unique_lock<ffrt::mutex> lock(hdiMutex_, std::defer_lock);
    lock.lock();
    if (gnssCallback_ == nullptr) {
        LBSLOGE(GNSS, "gnssCallback_ is nullptr");
        lock.unlock();
        return false;
    }
    int32_t ret = gnssInterface->EnableGnss(gnssCallback_);
    lock.unlock();
    LBSLOGD(GNSS, "Successfully enable_gnss!, %{public}d", ret);
    if (ret == 0) {
        gnssWorkingStatus_ = GNSS_WORKING_STATUS_ENGINE_ON;
    } else {
        gnssWorkingStatus_ = GNSS_WORKING_STATUS_NONE;
        WriteLocationInnerEvent(HDI_EVENT, {"errCode", std::to_string(ret),
            "hdiName", "EnableGnss", "hdiType", "gnss"});
    }
    return true;
}
  • 通过IPC通信,最终调用到服务端的实现,其中gnssInterface->enableGnss(&gnssCallback);对接的就是我们在适配层对这个方法的实现,在调用这个方法时还会向适配层传入一组回调,目的是当底层gps硬件有数据上报时,可以通过这组回调再将数据上报到HDI层。

//drivers/peripheral/location/gnss/hdi_service/gnss_interface_impl.cpp
int32_t GnssInterfaceImpl::EnableGnss(const sptr<IGnssCallback>& callbackObj)
{
    HDF_LOGI("%{public}s.", __func__);
    if (callbackObj == nullptr) {
        HDF_LOGE("%{public}s:invalid callbackObj", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    std::unique_lock<std::mutex> lock(g_mutex);
    const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<IGnssCallback>(callbackObj);
    if (remote == nullptr) {
        HDF_LOGE("%{public}s:invalid remote", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    static GnssCallbackStruct gnssCallback;
    GetGnssCallbackMethods(&gnssCallback);
    auto gnssInterface = LocationVendorInterface::GetInstance()->GetGnssVendorInterface();
    if (gnssInterface == nullptr) {
        HDF_LOGE("%{public}s:GetGnssVendorInterface return nullptr.", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    int ret = gnssInterface->enableGnss(&gnssCallback);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("enableGnss failed.");
        return HDF_FAILURE;
    }
//... ...
    return ret;
}
  • 从上面的流程图可以看出,GnssVendorInterface结构体是在HDI层定义,在adapter层实现的,这个结构体实例g_GVI_的实现是在适配时的关键一环,它是作为上层系统与底层硬件进行交互的桥梁。其中enableGnss与gnss_enable是一一对应的,在gnss_enable中,分为两部分操作,一方面是保存上面HDI层传递下来的回调,另一方面动态加载闭源库,并保存各闭源库函数地址,最后调用闭源库函数gps_init初始化硬件,需要注意的是,此时传入的回调并非上面HDI层传递过来的那组回调,而是另外又封装了一组回调,在这组回调中会调用HDI层传过来的回调进行数据上报。

//device/soc/spreadtrum/common/location/gnss/vendorGnssAdapter.cpp
void *g_Handle = NULL;
GnssCallbackStruct g_GCS_={0};
int gnss_enable(GnssCallbackStruct *callbacks) {
  LBSLOGE(GNSS, "%{public}s entered", GNSSMGT);
  if (callbacks == nullptr){
    LBSLOGE(GNSS, "%{public}s callbacks == nullptr return", GNSSMGT);
  }

  DL_RET ret=SO_OK;
  g_GCS_ = *callbacks;
  g_Handle = dlopen(GNSSMGT, RTLD_LAZY);
  LBSLOGE(GNSS, "%{public}s GNSSMGT handle addr is %x", GNSSMGT, g_Handle);

  if (g_Handle == NULL) 
  {
    LBSLOGE(GNSS, "%{public}s load failed", GNSSMGT);
    return LOAD_NOK;
  }

  gps_init = (pGnssmgt_init)dlsym(g_Handle, "gnssmgt_init");
  LBSLOGE(GNSS, "%{public}s gps_init addr is %{public}x", GNSSMGT, gps_init);

  gps_start = (pGnssmgt_start)dlsym(g_Handle, "gnssmgt_start");
  LBSLOGE(GNSS, "%{public}s gps_start addr is %{public}x", GNSSMGT, gps_start);

  gps_stop = (pGnssmgt_stop)dlsym(g_Handle, "gnssmgt_stop");
  LBSLOGE(GNSS, "%{public}s gps_stop addr is %{public}x", GNSSMGT, gps_stop);

  gps_cleanup = (pGnssmgt_cleanup)dlsym(g_Handle, "gnssmgt_cleanup");
  LBSLOGE(GNSS, "%{public}s gps_cleanup addr is %{public}x", GNSSMGT, gps_cleanup);

  agps_init = (pAGnssmgt_init)dlsym(g_Handle, "gnssmgt_agps_init");
  LBSLOGE(GNSS, "%{public}s agps_init addr is %{public}x", GNSSMGT, agps_init);

  agps_setPosMode = (pAGnssmgt_setPosMode)dlsym(g_Handle, "gnssmgt_setPosMode");
  LBSLOGE(GNSS, "%{public}s agps_setPosMode addr is %{public}x", GNSSMGT, agps_setPosMode);

//... ...
  if(gps_init==NULL||gps_start==NULL||gps_stop==NULL||gps_cleanup==NULL)
  {
	  LBSLOGE(GNSS, "functions load failed", GNSSMGT);
    return FUNC_NOK;
  }
  
  gps_init(&sGpsCallbacks);
  return ret;
}

二、定位数据上报

以GPS硬件状态变化时进行状态数据上报为例。

  • 当闭源库有数据需要上报时,会调用使能时传入的回调,比如硬件状态发生变化,会调用status_callback,在status_callback中再调用使能时HDI传递过来的那组回调中的gnssWorkingStatusUpdate将数据上报到HDI层。

//device/soc/spreadtrum/common/location/gnss/vendorGnssAdapter.cpp
static void status_callback(GpsStatus *status) {
  /* GNSS status unknown. */
  //  GNSS_STATUS_NONE = 0,
  /* GNSS has begun navigating. */
  //  GNSS_STATUS_SESSION_BEGIN = 1,
  /* GNSS has stopped navigating. */
  //  GNSS_STATUS_SESSION_END = 2,
  /* GNSS has powered on but is not navigating. */
  //  GNSS_STATUS_ENGINE_ON = 3,
  /* GNSS is powered off. */
  //  GNSS_STATUS_ENGINE_OFF = 4
  uint16_t ohos_status = status->status;
  g_GCS_.gnssCallback.gnssWorkingStatusUpdate(&ohos_status);
}
  • HDI层接收到数据之后,会再调用实现在系统服务层的回调将数据上报到系统服务层进行进一步处理。

//drivers/peripheral/location/gnss/hdi_service/gnss_interface_impl.cpp
static void GnssWorkingStatusUpdate(uint16_t* status)
{
    if (status == nullptr) {
        HDF_LOGE("%{public}s:param is nullptr.", __func__);
        return;
    }
    std::unique_lock<std::mutex> lock(g_mutex);
    GnssWorkingStatus gnssStatus = static_cast<GnssWorkingStatus>(*status);
    for (const auto& iter : g_locationCallBackMap) {
        auto& callback = iter.second;
        if (callback != nullptr) {
        	callback->ReportGnssWorkingStatus(gnssStatus);
        }
    }
}

这里只举了简单的硬件状态变化进行数据上报的流程,其他信息上报方式套路是相同的,只是在数据处理方面可能会有更多操作。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐