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的一个回调,便于两层之间传递数据。