打印
[资料分享]

安卓底层开发学习经验第二十七期

[复制链接]
870|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
这一期我们来看一下framework层和Hal层是如何来对接的,他们的对接不只是局限于我们的Sensor,还有camerasurface
首先framework层会有我们对于底层硬件支持的一系列服务,包括我们的CameraServiceSensorServiceAudioService,这三个库都是使用动态的方式去load我们Hal层的库,这个Hal层对下挂接的就是我们实际的设备,比如我们的cameraaudio等,那么这个Hal层对上层提供的接口是固定的,所以我们可以使用同一个接口来对我们底层进行访问,这个访问的过程就是通过get_Hal_opts()根据我们传输的名字,拿到我们Hal层操作的句柄。在Hal层的具体函数就是hw_get_module(),而他调用的是我们的hw_get_module_by_class(),也就是根据名字来加载我们所使用的动态库,我们Hal层真正的load动态库调用的是标准的dlopen()dlsym()的方式去拿到我们底层操作的句柄,在我们load库的过程中,我们的库基本是放在/system/lib/hw这个目录下,如果说我们有多个库,那么我们寻找库的先后顺序是根据Hal层中定义的结构里面去顺序获取的,如果我要加载一个SensorHal层的库,那么在这里会有一个libsensor.default.so,这个是我们默认的库,如果根据我们的prop里面没有获取到当前设备所对应的动态库,那么就会使用默认的库,如果我们系统的名字是全志,那么我们system/lib/hw下有一个全志的库,那么就会去load全志这个库。我们底层的device opts,也就是Hal层往下所对应的具体操作过程这时候就会有三个不同的实现,包括我们的Sensorcameraaudio或者其他的一些服务。这就是framework层和Hal层的一个对接关系。Hal层就是提供一个对上层的支撑,提供一个统一的接口,这样的话不管底层的库怎么换都没关系,因为接口都是标准的,只需要把这些接口封装起来,上层就不会关心具体底层是如何来实现,这就是Hal层的一个实现过程。
下面我们来看一下Android是如何寻找动态库和得到操作句柄的:1.首先在我们load动态库时会获取系统的prop,根据prop的具体值去我们的system/lib/hw的目录下查找相应的库。2.当我们获取到这个.so后,使用dlopen打开这个文件,然后使用dlsym来获取HMI,这个HMI是一个字符串,这个字符串会对应着我们库中的一个符号,这个符号就是hw_module的一个句柄。3.HMI是一个字符串,对应动态库中的一个符号,动态库是一个ELF的文件格式。4.ELF头在文件的开始,保存了路线图,描述了动态库文件组织的一个情况,包括指令、数据、符号表、重定位信息等。5.使用readelf -s sensors.default.so可以查看动态库符号信息,找到HMI符号。下面我们来看一下具体的load过程以及查找HMI的过程,打开hardware/libhardware/hardware.c
他就是给我们framework层调用的函数,他就会动态的load我们所传进来的字符串,以及根据字符串所匹配的load的库,我们来看一下这个hw_get_module_by_class()
我们来看一下他的参数,其中的class_id就是我们的sensorscamera或者audio的字符串,第二个可以忽略,第三个是hw_module_t的一个指针。当我们使用动态库获取到这个动态库中的句柄时,就会把这个句柄给我们的module,然后传给framework层,framework层就可以通过这个句柄来对我们Hal层进行操作。我们来看一下具体的load过程,首先会把path以及inst写进来,然后是property_get(),他的顺序首先是我们硬件的prop,然后是产品的prop,板子的prop,最后是ro.arch。如果有的话就会load这个库,如果每个都没有的话,它默认会load我们的名字,即Sensorcameraaudio.default.so。如果有这个名字,那么就去load这个库。我们看一下load的过程
首先是使用dlopen来打开这个文件,之后会有一个dlsym来获取这个动态库句柄中的一个结构,这个结构是HAL_MODULE_INFO_SYM_AS_STR,这个字符串就是HMI。当我们获取到这个句柄之后,就会把这个句柄赋给*pHmi,然后返回,这样的话我们的systemservice就能够拿到这个HMI的一个操作句柄。下面我们看一下HMI的具体实现。打开hardwar/invensense/65xx/libsensors_iio/sensors_mpl.cpp
HAL_MODULE_INFO_SYM这个就是我们导入phmi这结构体的一个句柄我们来看一下这个sensors_module_t这个结构体
他是我们通过动态库里面获取的句柄,这里面有两个重要的方法,第一个是我们的methods,这个是底层函数打开的一个函数,而get_sensors_list就是来获取底层所有支持的Sensor列表,这个会定义在本地,但是到时候会根据硬件(sensors_module_methods)实际打开的Sensor来做依据,而sensors_get_sensors_list只是一个假定义的一个列表。在sensors_module_methods里面有一个结构体,这个结构体是open_sensors
他在这里new了一个sensors_poll_context_t(),在new的时候会打开Sensor的所有设备,我们来看一下sensors_poll_context_t()的具体定义方法,他会把我们的Sensornew出来,而我们每一个Sensor对应的都是我们底层的一个具体的设备,然后去打开设备,还有一系列的操作函数,这就是sensors_poll_context_t()所做的事情。下面我们来看一下Hal层的具体操作过程
首先SensorDevice会使用我们的sensors_open_1的方法去获取一个句柄,这个句柄就是我们的mSensorDevice,获取之后会通过具体的方法(sensors_module_methods)来打开我们底层的Sensor,这个方法就是open_sensors,而open_sensors设置了mSensorDeviceoptsOpts包括着我们对Sensor的所有的操作,包括我们的ActivitysetDelaypoll。这样的话我们直接通过mSensorDevice对我们Sensor进行操作就可以了。下面我们再来看一下Sensor的一个数据流程
从上面来看,首先要注册一个Listener,然后SensorManagerjava)层通过JNI调用我们c++层的SensorManager,然后再通过binder机制和我们的SensorServer进行交互,而我们的数据是通过一个套接字来进行交互的,SensorServer是通过Hal层的对接来获取我们底层Sensor操作的一个结构,也就是我们的SensorDevice来获取得到Sensor数据的一个接口,通过这个接口将数据返回给SensorServer,然后SensorServer再通过SendSensorEvent的方法通过socket发送给我们的SensorManager,然后他在通过回调的方法发送给SensorManagerjava),这个SensorManager同样会有一个Listener监听,调用onSensorChanged()的方法报给我们上层的应用。上层应用获取到这些数据以后,就会自己做处理。这就是Android Sensor的一个具体实现。
那么如果说我们想要加一个自己的Sensor,那么所需要做的事情是:首先要修改Sensor Hal层以下的部分,这部分需要添加一个sensorList列表,需要我们添加自己Sensor的名字,然后我们要在底层打开我们的设备,对底层设备进行一下封装,包括我们的open函数、Poll方法、Activity方法以及setdelay方法,这样就可以把这个接口封装给Hal层,然后Hal层再通过上层systemservice的一个调用,完成整个Sensor的构建。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

315

帖子

16

粉丝