Android
GPS数据流程分析
概述:
该文档将介绍android
GPS数据流程分析,在debug的时候可以做为数据流的捕捉的参考。
=============================================================
在介绍数据流之前首先介绍的数据在hal层究竟从哪里来的,也就是原生的没经过解码的数据时从哪儿来的,首先进入到hardware下创建RPC通讯的地方开始,也就是创建一个RPC
client,也就是loc_api_glue_init函数做这件事情:
进入到loc_api_glue_init=>
clnt_create:
CLIENT
*clnt_create(
char
* host,
uint32
prog,
uint32
vers,
char
* proto)
{
…………………………………………………………….
client->xdr
=xdr_init_common(name,
1 /* client XDR */);
…………………………………………………………………
if
(!num_clients++) {
D("launching
RX thread.\n");
pthread_create(&rx_thread,
NULL,rx_context,NULL);
}
else {
/*
client added, wake up rx_thread */
if
(write(wakeup_pipe[1], "a", 1) < 0)
E("error
writing to pipe\n");
}
……………………………………………………………………
}
NOTE:XDR是一个数据描述和数据编码的标准,它对于不同架构计算机之间的数据传输是非常有用的。
RPC是计算机之间的远过程调用协议。
RPC使用XDR描述它的数据格式的。
=============================================================
这个函数有两个功能:
初始化相关的XDR读取RPC数据的方法。
创建一个线程rx_context去接收RPC的数据。
对于前者主要的:
xdr_s_type
*xdr_init_common(const char *router, int is_client)
{
xdr_s_type
*xdr = (xdr_s_type *)calloc(1, sizeof(xdr_s_type));
xdr->xops
= &xdr_std_xops;
……………………………
return
xdr;
}
实际上xdr_std_xops是xdr操作的各种方法
const
xdr_ops_s_type xdr_std_xops = {
xdr_std_destroy,
xdr_std_control,
xdr_std_read,//读数据
xdr_std_msg_done,
xdr_std_msg_start,
xdr_std_msg_abort,
xdr_std_msg_send,
/*数据编码*/
xdr_std_send_int8,
xdr_std_send_uint8,
xdr_std_send_int16,
xdr_std_send_uint16,
xdr_std_send_int32,
xdr_std_send_uint32,
xdr_std_send_bytes,
/*数据解码*/
xdr_std_recv_int8,
xdr_std_recv_uint8,
xdr_std_recv_int16,
xdr_std_recv_uint16,
xdr_std_recv_int32,
xdr_std_recv_uint32,
xdr_std_recv_bytes,
};
对于后者创建一个线程去读取RPC数据:
static
void *rx_context(void *__u __attribute__((unused)))
{
……………………………………………..
ret
= client->xdr->xops->read(client->xdr);
if
(ret == FALSE) {
E("%08x:%08x
xops->read() error %s (%d)\n",
client->xdr->x_prog,
client->xdr->x_vers,
strerror(errno),
errno);
……………………………………………….
}
通过ret
= client->xdr->xops->read(client->xdr);读取rpc数据,这个read函数的
注册实际上就在xdr_init_common里面,那么到这个我已经知道数据从哪儿来的了,后面介绍jni与hal层交互的数据过程:
回到hardware/qcom/gps/loc_api/libloc_api/loc_eng.cpp的loc_eng_init
中的loc_eng_data.client_handle
= loc_open (event, loc_event_cb);
这个函数主要的目的是打开前面创建的rpc
client并把相关的数据提交上报的
过程:
首先看loc_event_cb这个函数,
static
int32 loc_event_cb( )
{
if
(client_handle == loc_eng_data.client_handle)
{
………………………………………………..
memcpy(&loc_eng_data.loc_event_payload,
loc_event_payload, sizeof(*loc_event_payload));
………………………………………………..
pthread_cond_signal
(&loc_eng_data.deferred_action_cond);
pthread_mutex_unlock
(&loc_eng_data.deferred_action_mutex);
}
}
这个函数主要完成的功能是
1、将接收到的数据搬移
2、发送一个信号给处理这个数据的线程
进到处理这个数据的线程:
进入到这个函数中loc_eng_process_deferred_action,这也是一个线程专门用于处理数据,在init的时候被创建:
调用函数loc_eng_process_deferred_action=>
loc_eng_report_position真正的实现数据的上报到jni层,进入到函数loc_eng_report_position看看:
static
void loc_eng_report_position (const rpc_loc_parsed_position_s_type
*location_report_ptr)
{
GpsLocation
location;
……………………………………………………
if
(location_report_ptr->valid_mask &
RPC_LOC_POS_VALID_HOR_UNC_CIRCULAR)
{
location.flags
|= GPS_LOCATION_HAS_ACCURACY;
location.accuracy
= location_report_ptr->hor_unc_circular;
}
if
(loc_eng_data.location_cb != NULL)
{
LOGV
("loc_eng_report_position: fire callback\n");
loc_eng_data.location_cb
(&location);
}
}
}
最关键的是loc_eng_data.location_cb
(&location);调用这个函数的时候相当于真正调的是jni注册到hal的函数,通过这种方式就实现了jni与hal的数据传递了。
再回到loc_open这个函数:
在loc_open中将通过这句话loc_glue_callback_table[i].cb_func
= event_callback;
将loc_event_cb注册给了loc_glue_callback_table[i],那么什么时候真正的调用呢?
在qcom/proprietary/gps/loc_api/libloc-rpc/src/loc_api_rpc_glue.c的
rpc_loc_event_cb_f_type_svc中实现了真正的调用,
后续的调用关系如下:
rpc_loc_event_cb_f_type_svc=>RPC_CALLBACK_FUNC_VERSION(rpc_loc_event_cb_f_type_,
RPC_LOC_EVENT_CB_F_TYPE_VERSION, _svc) =>
rpc_loc_event_cb_f_type_0x00050001_svc
在qcom/proprietary/modem-apis/msm7627_ktouch/api/libs/remote_apis/loc_api/rpcgen/src/loc_api_rpcgen_cb_svc.c
+45
有函数loc_apicbprog_0x00050001将rpc_loc_event_cb_f_type_0x00050001_svc
赋值给了local,后面通过retval
= (bool_t) (*local)((char *)&argument, (void *)&result,
rqstp)实现对rpc_loc_event_cb_f_type_0x00050001_svc真正的调用,
Argument中的内容就是转换之后的数据指针,从哪儿来的呢?
通过svc_getargs这个函数实现的,svc_getargs中的参数_xdr_argument得到了调用,也就是xdr_rpc_loc_event_cb_f_type_args得到了调用,进入这个函数看看:
bool_t
xdr_rpc_loc_event_cb_f_type_args
(XDR *xdrs, rpc_loc_event_cb_f_type_args *objp)
{
if
(!xdr_rpc_uint32(xdrs, &objp->cb_id))
return
FALSE;
if
(!xdr_rpc_loc_client_handle_type (xdrs, &objp->loc_handle))
return
FALSE;
if
(!xdr_rpc_loc_event_mask_type (xdrs, &objp->loc_event))
return
FALSE;
if
(!xdr_pointer (xdrs, (char **)&objp->loc_event_payload, sizeof
(rpc_loc_event_payload_u_type), (xdrproc_t)
xdr_rpc_loc_event_payload_u_type))
return
FALSE;
return
TRUE;
}
也就是xdr_rpc_uint32实现了数据的解码过程
=============================================================
到这里将hal层与jni层的通讯数据的传递分析完了,后面分析jni层的数据时怎么到java层的:
进入jni的函数里面:
进入android_location_GpsLocationProvider_wait_for_event这个函数:
比如位置的信息的上报时通过什么方式的,截取了一段程序如下:
if
(pendingCallbacks & kLocation) {
env->CallVoidMethod(obj,method_reportLocation,sGpsLocationCopy.flags,
(jdouble)sGpsLocationCopy.latitude,
(jdouble)sGpsLocationCopy.longitude,
(jdouble)sGpsLocationCopy.altitude,
(jfloat)sGpsLocationCopy.speed,
(jfloat)sGpsLocationCopy.bearing,
(jfloat)sGpsLocationCopy.accuracy,
(jlong)sGpsLocationCopy.timestamp);
首先当这个线程得到信号sEventCond后就会进入到运行状态,被谁唤醒呢?就是hal掉init的jni的相关回调结束的时候会发送一个信号给该线程,实现线程的同步,
注意到当判断到时位置信息的时候进入到这个分支,调用method_reportLocation这个方法将数据上报,为什么呢?看jni里面这句话
method_reportLocation
= env->GetMethodID(clazz, "reportLocation",
"(IDDDFFFJ)V");
也就是说method_reportLocation映射为java层的reportLocation这种方法,所以
reportLocation这个方法实现在GpsLocationProvider.java中
private
void reportLocation(int flags, double latitude, double longitude,
double altitude,
float
speed, float bearing, float accuracy, long timestamp) {
if
(VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + "
long: " + longitude +
"
timestamp: " + timestamp);
mLastFixTime
= System.currentTimeMillis();
…………………………………………………..
}
到这里数据就已经到java层了。reportLocation这个函数可以认为是java层注册到jni的一个回调,便于两层之间传递数据。