Chinaunix首页 | 论坛 | 博客
  • 博客访问: 284148
  • 博文数量: 86
  • 博客积分: 694
  • 博客等级: 上士
  • 技术积分: 833
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-31 16:40
文章分类

全部博文(86)

文章存档

2012年(75)

2011年(6)

2010年(5)

分类: LINUX

2010-12-31 18:03:58

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");

}

……………………………………………………………………

}

NOTEXDR是一个数据描述和数据编码的标准,它对于不同架构计算机之间的数据传输是非常有用的。

RPC是计算机之间的远过程调用协议。

RPC使用XDR描述它的数据格式的。

=============================================================

这个函数有两个功能:

  1. 初始化相关的XDR读取RPC数据的方法。

  2. 创建一个线程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_xopsxdr操作的各种方法

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里面,那么到这个我已经知道数据从哪儿来的了,后面介绍jnihal层交互的数据过程:


回到hardware/qcom/gps/loc_api/libloc_api/loc_eng.cpploc_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的函数,通过这种方式就实现了jnihal的数据传递了。

再回到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_0x00050001rpc_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后就会进入到运行状态,被谁唤醒呢?就是halinitjni的相关回调结束的时候会发送一个信号给该线程,实现线程的同步,

注意到当判断到时位置信息的时候进入到这个分支,调用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的一个回调,便于两层之间传递数据。


阅读(4119) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~