快一个月没更文了,这一个月都在处理一个事情,在高通Android11平台上移植GNSS功能,中间涉及到很多技术细节,遂记录一下。
首先要搞清楚两个问题
什么是GNSS
这里我简单说明一下,GNSS全称是Global Navigation Satellite System,翻译过来叫全球定位卫星导航系统。那它跟我们常说的GPS是啥关系呢?实际上GNSS泛指所有的卫星导航系统,包括全球的、区域的和增强的,GPS只是GNSS其中的一种,除了GPS,还有中国的北斗卫星导航系统,俄罗斯的Glonass,欧洲的Galileo等。
为什么要往Android平台上移植GNSS
从大的概念来说,Google的Android平台其实也只是提供了一个标准,它并不会对接具体的硬件厂商,所以Android系统其实可以说是一个空壳,需要什么样的功能就往上面移植什么功能,比如GNSS,Camera,Sensor,Audio,Video,Display等,而本人最近就负责公司某个项目的GNSS上层移植工作。
准备工作
移植工作大致分以下几个部分:
- 硬件移植,确定移植哪个厂商的硬件
- 驱动移植,确定Kernel层与HAL层的通信协议,本文采用的UART通信,除此之外还可以使用RIL通信
- HAL移植,解析NMEA数据,给上层提供接口,供HIDL和JNI调用
- 适配Selinux,添加访问驱动节点的权限
- 应用层测试验证,安装GPS测试工具(高德地图等),测试是否能够获取定位数据
本人主要负责步骤3~步骤5,HAL移植首先要得到该厂商对应的库文件,因为每个厂商的标准不一样,所以解析NMEA数据的方式也不太一样,所以这个必须要厂家提供,可以是c/c++源文件,也可以是编译好的so库,本人参与的项目是采用so。硬件准备好了,驱动调好了,拿到了厂商库文件,上层就可以开始移植了。
关于NMEA(National Marine Electronics Association),它是为海用电子设备制定的标准格式,GNSS通信数据也采用这种格式,大概长这样
具体格式定义可参考《NMEA协议说明及解析》
开始移植
-
首先在device目录下配置so库和UART配置文件的存放路径,同时添加对应的HAL层服务
PRODUCT_PACKAGES += \ android.hardware.gnss@1.0-impl \ android.hardware.gnss@1.0-service # Add for gps.default.so PRODUCT_COPY_FILES += \ vendor/gps/lib64/gps.default.so:vendor/lib64/hw/gps.default.so \ vendor/gps/lib64/gps_cfg.inf:vendor/etc/gps_cfg.inf
注意这里so库的命名不是随意的,
gps_cfg.inf
中主要是配置UART节点名称和波特率NMEA_PORT_PATH=/dev/ttyXXX BAUD_RATE=115200
-
注册hal服务,类似Android四大组件一样,hal服务也需要在
manifest.xml
文件中注册<!-- gnss --> <hal format="hidl"> <name>android.hardware.gnss</name> <transport>hwbinder</transport> <version>1.0</version> <interface> <name>IGnss</name> <instance>default</instance> </interface> <fqname>@1.0::IGnss/gnss_vendor</fqname> </hal>
注意,除了要在
manifest.xml
中注册,还需要在compatibility_matrix.N.xml
中注册,原因参见Google官网说明,其中N为最新的版本号。<hal format="hidl" optional="true"> <name>android.hardware.gnss</name> <version>1.0</version> <interface> <name>IGnss</name> <instance>default</instance> </interface> </hal>
注意两个文件中的version版本号要一致,否则会编译失败
-
删除厂商自带的GNSS配置,本人调试的是高通平台的,高通平台自带GNSS,现在移植其他厂商的GNSS后要将高通的配置删除掉。这个就不代码演示了,直接全局搜索高通的
vendor.xxx.gnss
,xxx为厂商名称,然后将其删除即可。 -
到这一步,可以先编译验证一下,看能不能获取到定位数据,这时在开机log中会出现大量有关gnss权限的日志
04-21 09:01:33.647 415 415 W gnss@1.0-servic: type=1400 audit(0.0:24): avc: denied { read write } for name="ttyXXX" dev="tmpfs" ino=13516 scontext=u:r:hal_gnss_default:s0 tcontext=u:object_r:vendor_location_device:s0 tclass=chr_file permissive=0
并且通过GPS测试工具是获取不到定位数据的,上述日志是典型的selinux错误日志,关于selinux,这里不做具体讲解,可参考《Android安全策略SELinux》,这里日志的大概意思就是
hal_gnss_default
要访问vendor_location_device
需要{ read write }
权限,这种情况一般根据日志去添加权限就可以了,在device目录下配置allow hal_gnss_default vendor_location_device:chr_file { read write open };
这里贴一张selinux配置的个人经验方法图
- 权限添加完毕之后,编译验证,使用GPS测试工具,成功获取到定位数据
GPS测试工具下载链接放到文末了,当然,也可以使用高德地图测试
因为网络功能相关同事还在调试中,暂时还不能上网,所以这里只能看到定位小蓝点,显示不了地图
灵魂拷问
看到这里,你可能不禁要问,就这么点工作,还要搞一个月吗?肯定摸鱼了。啊,这个要怎么说呢,首先第一,移植方案落地之前肯定需要花大量的时间去做准备工作,比如从上层到底层,gnss的通信流程,这个你得搞明白
这里我单独整理了一篇文章《浅析Android11 Gnss定位流程》
其次,因为涉及到跨厂商联调,这个难度跟客户做过联调的朋友应该都知道。然后因为涉及到权限te文件和makefile文件,只能全编译验证,我这个机器配置,Android 11首次全编译所需要的时间大概是5个小时,后面增量编译也要一二十分钟,所以这个也很费时间。最后,因为是公司内部项目,还涉及到一些内部问题,比如,高速URAT相比于普通URAT,需要额外的配置,这个作为framework开发,跟BSP开发沟通起来真的是困难,因为彼此都不太懂对方的工作内容。
拓展
移植期间,深入学习了一下GPS,拜读了这篇文章《GPS定位技术》,里面讲解了GPS定位原理,地图投影,时间系统,位置计算方法,GPS系统组成,定位产生误差的原因及减少误差的方法等等,虽然有些公式性的知识不太懂,但十分感叹博主知识面之广,不得不佩服,强烈推荐大家也去拜读一下。
附件
GPS测试工具:
链接: pan.baidu.com/s/1xvmwxFi0… 提取码: 5y61 复制这段内容后打开百度网盘手机App,操作更方便哦