android9:GPS模块-源码调用流程

参考文章:https://blog.csdn.net/grekit_sun/article/details/109469351
参考:https://blog.csdn.net/pangsurong/article/details/73912714?utm_medium=distribute.pc_relevant.none-task-blog-title-11&spm=1001.2101.3001.4242
参考:https://blog.csdn.net/weixin_45244289/article/details/109529004
重要:GPS模块Hal层修改。https://baijiahao.baidu.com/s?id=1677587863744470911&wfr=spider&for=pc

一、源码层级
1、HAL层:
/home/lily/android_build_9/hardware/qcom/gps/loc_api/libloc_api_50001/gps.c
/home/lily/android_build_9/hardware/libhardware/include/hardware/gps.h
1)HAL 层标准接口
HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。

为了保证 HAL 具有可预测的结构,每个硬件专用 HAL 接口都要具有在 hardware/libhardware/include/hardware/hardware.h 中定义的属性。这类接口可让 Android 系统以一致的方式加载 HAL 模块的正确版本。HAL 接口包含两个组件:模块和设备。

模块:
模块代表打包的 HAL 实现,这种实现存储为共享库 (.so file)。hardware/libhardware/include/hardware/hardware.h 头文件可定义一个代表模块的结构体 (hw_module_t),其中包含模块的版本、名称和作者等元数据。Android 会根据这些元数据来找到并正确加载 HAL 模块。

另外,hw_module_t 结构体还包含指向另一个结构体 hw_module_methods_t 的指针,后面这个结构体包含指向相应模块的 open 函数的指针。此 open 函数用于与相关硬件(此 HAL 是其抽象形式)建立通信。

typedef struct hw_module_t {} hw_module_t;

typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;

设备:
设备是产品硬件的抽象表示。

设备由 hw_device_t 结构体表示。与模块类似,每类设备都定义了一个通用 hw_device_t 的详细版本,其中包含指向特定硬件功能的函数指针。

typedef struct hw_device_t {}hw_device_t 

2、HIDL层:
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/IGnssCallback.hal
/home/lily/android_build_9/hardware/interfaces/gnss/1.1/IGnssCallback.hal
hidl的官方标准定义为:HIDL是HAL接口定义语言(简称 HIDL,发音为“hide-l”),是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL)。

安卓官方设计 HIDL 这个机制的目的,主要是想把框架(framework)与 HAL 进行隔离,使得框架部分可以直接被覆盖、更新,而不需要重新对 HAL 进行编译。

客户端和服务器实现
HIDL 接口具有客户端和服务器实现:

  • HIDL 接口的客户端实现是指通过在该接口上调用方法来使用该接口的代码。

  • 服务器实现是指 HIDL 接口的实现,它可接收来自客户端的调用并返回结果(如有必要)。
    在从libhardware HAL 转换为 HIDL HAL 的过程中,HAL 实现成为服务器,而调用 HAL 的进程则成为客户端。默认实现可提供直通和 Binder 化 HAL。
    在这里插入图片描述
    上图为HAL的几个发展历程,方式2为目前我的开发环境所使用的直通方式,框架和HAL之间通过HIDL接口实现通信,硬件厂商负责服务器的实现。

系统服务启动gps.ublox.so
下面从系统服务方面介绍一下系统启动,获取gps.ublox.so(gps hal驱动编译生成的文件)流程。

①、首先介绍GNSS的HIDL接口,编译生成"android.hardware.gnss@1.0"接口共享库,客户端和服务器之间就是通过这些接口来工作的,服务器端需要做的就是实现该接口。
接口编译脚本如下:
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/Android.bp
②、rc文件启动服务android.hardware.gnss@1.0-service
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
android.hardware.gnss@1.0-service.rc启动服务android.hardware.gnss@1.0-service

service vendor.gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
    class hal
    user gps
    group system gps radio

android.hardware.gnss@1.0-service服务由Android.bp编译得到,其次还包含了HIDL接口"android.hardware.gnss@1.0"。
Android.bp路径:
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/Android.bp

cc_binary {
    relative_install_path: "hw",
    vendor: true,
    name: "android.hardware.gnss@1.0-service",
    defaults: ["hidl_defaults"],
    init_rc: ["android.hardware.gnss@1.0-service.rc"],
    srcs: ["service.cpp"],

    shared_libs: [
        "liblog",
        "libcutils",
        "libdl",
        "libbase",
        "libutils",
        "libhardware",
        "libbinder",
        "libhidlbase",
        "libhidltransport",
        "android.hardware.gnss@1.0",
    ],

}

编译所需的源文件为service.cpp
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/service.cpp

service.cpp,它将对提供的-impl 库执行dlopen() 操作,并将其作为 Binder 化服务提供,service.cpp代码如下:

#define LOG_TAG "android.hardware.gnss@1.0-service"
#include <android/hardware/gnss/1.0/IGnss.h>
#include <hidl/LegacySupport.h>
#include <binder/ProcessState.h>
using android::hardware::gnss::V1_0::IGnss;
using android::hardware::defaultPassthroughServiceImplementation;

int main() {
    // The GNSS HAL may communicate to other vendor components via
    // /dev/vndbinder
    android::ProcessState::initWithDriver("/dev/vndbinder");
    return defaultPassthroughServiceImplementation<IGnss>();
}

③、"android.hardware.gnss@1.0-impl"是接口的具体实现。
-impl 库也由Android.bp编译而成
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/Android.bp
其部分内容如下:

cc_library_shared {
    name: "android.hardware.gnss@1.0-impl",
    defaults: ["hidl_defaults"],
    vendor: true,
    relative_install_path: "hw",
    srcs: [
        "ThreadCreationWrapper.cpp",
        "AGnss.cpp",
        "AGnssRil.cpp",
        "Gnss.cpp",
        "GnssBatching.cpp",
        "GnssDebug.cpp",
        "GnssGeofencing.cpp",
        "GnssMeasurement.cpp",
        "GnssNavigationMessage.cpp",
        "GnssNi.cpp",
        "GnssXtra.cpp",
        "GnssConfiguration.cpp",
        "GnssUtils.cpp",
    ],

    shared_libs: [
        "liblog",
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "android.hardware.gnss@1.0",
        "libhardware",
    ],

}

④、HIDL_FETCH_IModuleName 函数
为了让 HAL 在直通模式下运行,Gnss.cpp 必须具有 HIDL_FETCH_IModuleName 函数
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/Gnss.cpp

IGnss* HIDL_FETCH_IGnss(const char* /* hal */) {
    hw_module_t* module;
    IGnss* iface = nullptr;
    int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

    if (err == 0) {
        hw_device_t* device;
        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
        if (err == 0) {
            iface = new Gnss(reinterpret_cast<gps_device_t*>(device));
        } else {
            ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
        }
    } else {
      ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
    }
    return iface;
}

这个函数会加载gps.ublox.so库。

3、jni 层:
jni是framework与hidl hal之间的一层,为java语言实现的framework调用c++语言实现的hidl hal代码提供接口。/home/lily/android_build_9/frameworks/base/core/jni

4、Application Framework层:
/home/lily/android_build_9/frameworks/base/location/java/com/android/internal/location
/home/lily/android_build_9/frameworks/base/services/core/java/com/android/server/LocationManagerService.java
5、Application

二、GPS启动流程
在这里插入图片描述

1、在SystemServer.java中添加定位服务并通过systemrunning开启
/home/lily/android_build_9/frameworks/base/services/java/com/android/server/SystemServer.java(application framework层)

     /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run() {
         // Start services.
        try {
            startOtherServices();
        }catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
    }
  private void startOtherServices() {
     //添加LocationManagerService到ServiceManager
     traceBeginAndSlog("StartLocationManagerService");
            try {
                location = new LocationManagerService(context);
                ServiceManager.addService(Context.LOCATION_SERVICE, location);
            } catch (Throwable e) {
                reportWtf("starting Location Manager", e);
            }
            traceEnd();
     
     final LocationManagerService locationF = location;
     //调用LocationManagerService中systemRunning方法,准备provider
     traceBeginAndSlog("MakeLocationServiceReady");
            try {
                if (locationF != null) {
                    locationF.systemRunning();
                }
            } catch (Throwable e) {
                reportWtf("Notifying Location Service running", e);
            }
            traceEnd();
  }

2、调用LocationManagerService类中systemrunning方法,准备provider。
/home/lily/android_build_9/frameworks/base/services/core/java/com/android/server/LocationManagerService(application framework层)

 public void systemRunning() {
        synchronized (mLock) {
            initializeLocked();
        }
}

@GuardedBy("mLock")
private void initializeLocked() {
    // prepare providers
    initializeProvidersLocked();
}

@GuardedBy("mLock")
    private void initializeProvidersLocked() {
        // create a passive location provider, which is always enabled
        LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
        addProviderLocked(passiveProviderManager);
        mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
        passiveProviderManager.attachLocked(mPassiveProvider);

        if (GnssLocationProvider.isSupported()) {
            // Create a gps location provider
            LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
            mRealProviders.add(gnssProviderManager);
            addProviderLocked(gnssProviderManager);

            GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
                    gnssProviderManager,
                    mHandler.getLooper());
            gnssProviderManager.attachLocked(gnssProvider);

            mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
            mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
            mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
            mGnssCapabilitiesProvider = gnssProvider.getGnssCapabilitiesProvider();
            mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
            mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
            mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
            mGnssMeasurementCorrectionsProvider =
                    gnssProvider.getGnssMeasurementCorrectionsProvider();
            mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
            mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
        }
   }

(1)这里只针对GPS,所以只贴了GNSS的相关代码。其实加载的供应者还有passive,fuse,network相关的provider,请自行分析。
(2)加载之前首先要判断是否支持GNSS,其实在调用isSupproted之前,Gnss对providers做初始化工作,即图中的class_init_naitve。若是支持的话,isSupported肯定返回的是true,然后建立GnssLocationProvider对象,并加入链表记录下来。
(3)updateProvidersLocked--》updateProviderListenersLocked
该步骤的功能会根据相应的provider的开启状态进行关闭或开启。例如,若Gnss未开启,则会执行p.enable()开启Gnss。

3、获取GnssLocationProvider.java实例调用class_init_native方法(调用到jni层)
/home/lily/android_build_9/frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java

private static native boolean native_is_supported();
static {
        class_init_native();
}

public static boolean isSupported() {
        return native_is_supported();
}

class_init_native方法是一个静态方法,会在isSupported()方法之前被调用。最终会调用到native函数com_android_server_location_GnssLocationProvider中android_location_GnssLocationProvider_class_init_native方法。
/home/lily/android_build_9/frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp(jni层/native层)

jni获取hidl接口函数如下:

static const JNINativeMethod sMethods[] = {
   {"native_is_supported", "()Z", reinterpret_cast<void *>(
            android_location_GnssLocationProvider_is_supported)},
}
/* One time initialization at system boot */
static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
    // Initialize the top level gnss HAL handle.
    android_location_GnssLocationProvider_set_gps_service_handle();
}

/* Initializes the GNSS service handle. */
static void android_location_GnssLocationProvider_set_gps_service_handle() {
    gnssHal_V2_0 = IGnss_V2_0::getService();
    if (gnssHal_V2_0 != nullptr) {
        gnssHal = gnssHal_V2_0;
        gnssHal_V1_1 = gnssHal_V2_0;
        return;
    }

    ALOGD("gnssHal 2.0 was null, trying 1.1");
    gnssHal_V1_1 = IGnss_V1_1::getService();
    if (gnssHal_V1_1 != nullptr) {
        gnssHal = gnssHal_V1_1;
        return;
    }

    ALOGD("gnssHal 1.1 was null, trying 1.0");
    gnssHal = IGnss_V1_0::getService();
}

static jboolean android_location_GnssLocationProvider_is_supported(
        JNIEnv* /* env */, jclass /* clazz */) {
    return (gnssHal != nullptr) ?  JNI_TRUE : JNI_FALSE;
}

4、设置回调函数

在安卓GPS架构中,非常重要的,无疑不是回调操作了。所有GPS的上报,都是通过回调函数完成的。它的gps数据回调流程是:hal->hidl->jni,可以看到,所谓回调,其实就是由下而上。不过,设置回调结构体却是由上而下:jni->hidl->hal。

安卓gps标准回调结构体,如下路径:
/home/lily/android_build_9/hardware/libhardware/include/hardware/gps.h(HAL层)
以下是在标准结构体基础上添加的回调,用于回调加速度、陀螺仪的信息,在标准结构体中没有这两行。


typedef struct {
    /** set to sizeof(GpsCallbacks) */
    size_t      size;
    gps_location_callback location_cb;
    gps_status_callback status_cb;
    gps_sv_status_callback sv_status_cb;
    gps_nmea_callback nmea_cb;
    gps_set_capabilities set_capabilities_cb;
    gps_acquire_wakelock acquire_wakelock_cb;
    gps_release_wakelock release_wakelock_cb;
    gps_create_thread create_thread_cb;
    gps_request_utc_time request_utc_time_cb;
    gnss_gyr_callback gyr_cb;//新加
	gnss_acc_callback acc_cb;//新加
    gnss_set_system_info set_system_info_cb;
    gnss_sv_status_callback gnss_sv_status_cb;
} GpsCallbacks;
 

填充回调函数指针
因为gps hal层驱动上报信息需要用到回调结构体,而这个结构体则需要hidl层定义实现这个结构体,然后再传递给hal层,让hal层得到这个结构体指针。而hidl回调到jni层,也需要jni定义并传递一个类似的回调结构体。所以,接下来,我们就来看一下,代码中是如何填充回调函数指针的。
①、hidl hal
/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/Gnss.cpp


GpsCallbacks Gnss::sGnssCb = {
    .size = sizeof(GpsCallbacks),
    .location_cb = locationCb,
    .status_cb = statusCb,
    .sv_status_cb = gpsSvStatusCb,
    .nmea_cb = nmeaCb,
    .set_capabilities_cb = setCapabilitiesCb,
    .acquire_wakelock_cb = acquireWakelockCb,
    .release_wakelock_cb = releaseWakelockCb,
    .create_thread_cb = createThreadCb,
    .request_utc_time_cb = requestUtcTimeCb,
    .set_system_info_cb = setSystemInfoCb,
    .gnss_sv_status_cb = gnssSvStatusCb,
    .gyr_cb = gnssGyrCb,
    .acc_cb = gnssAccCb,
};
 
Return<bool> Gnss::setCallback(const sp<IGnssCallback>& callback)
{
    ……
    sGnssCbIface = callback;
    ……
    return (mGnssIface->init(&sGnssCb) == 0);
}

可以看到return中调用了mGnssIface->init函数,mGnssIface就是gps hal层的接口,最后提到HAL接口调用。

我们继续看mGnssIface->init函数是如何实现的,代码内容如下:

5、获取GPS驱动接口
hidl层获取hal层接口
hidl文件位置/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/Gnss.cpp。
hal层文件位置/home/lily/android_build_9/hardware/qcom/gps。

前文可知,系统服务起来之后,hidl层最开始运作起来的地方就是HIDL_FETCH_IModuleName函数了,通过名字,我们可以知道,这个函数的意思是获取模块名,换句话来说,也就是获取前面提到过的“hw_module_t”和“hw_device_t”这两个结构体。

我们先看到这个HIDL_FETCH_IModuleName函数第5行,这里调用了hw_get_module函数,这个函数会根据GPS_HARDWARE_MODULE_ID去找到对应的“hw_module_t”,

/home/lily/android_build_9/hardware/interfaces/gnss/1.0/default/Gnss.cpp

IGnss* HIDL_FETCH_IGnss(const char* /* hal */) {
    hw_module_t* module;
    IGnss* iface = nullptr;
    int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

    if (err == 0) {
        hw_device_t* device;
        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
        if (err == 0) {
            iface = new Gnss(reinterpret_cast<gps_device_t*>(device));
        } else {
            ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
        }
    } else {
      ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
    }
    return iface;
}

hal驱动层“hw_module_t”如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值