HAL中通过JNI调用java方法【转】
转载请注明本文出处:http://www.cnblogs.com/xl19862005
作者:Xandy
由于工作的需要,最近一直在研究HAL、JNI、Java方法之间互调的问题,并做了如下一些记录和大家一起分享!
工作背景:所调试的是一款叫goc-md-102的车载蓝牙模块,由于这款蓝牙模块无法直接用HCI的方式控制,而它已经有了现成的一套AT命令集进行控制,所以我在HAL中直接通过串口读写的方式进行通信,然后通过JNI和java层建立联系。
考虑到效率的问题,我在HAL中用回调函数的方式通过JNI与java层交换数据,看了一下GPS数据上报的方法正和我用的这个方法一样!
1、首先是在HAL中串口的开启、初始化和读写,这些都比较简单,主要看看初始化这个函数中的代码,如下:
/***************************************************************
** fun: init gocmd102_init(/dev/ttymxc1);
** in:
** out: fd sucess, -1 false;
** gocmd102_init
***************************************************************/
static int gocmd102_init(BluetoothCallback *callBack)
{
int fd,var;
btportinfo pPort_info;
int err; pReceiveCmdPackage = malloc(sizeof(bluetooth)); memset(pReceiveCmdPackage,0,sizeof(bluetooth));
memset(recCmdBuf,0,RECCMDBUFLEN);
//clear message buf
memset(&pPort_info,0,sizeof(btportinfo)); fd=open_bluetoothPort(); if(fd < 0)
{
LOGE("gocmd102_init open port error!");
return -1;
} pReceiveCmdPackage->fd= fd;
FD = fd; pPort_info.baud_rate=GOCMD102_BAUD;
pPort_info.data_bits=GOCMD102_DATABIT;
pPort_info.flow_ctrl=GOCMD102_CTRL;
pPort_info.stop_bit=GOCMD102_STOPBIT;
pPort_info.parity=GOCMD102_PARITY;
pPort_info.port_fd=fd; //pthread_mutex_lock(&pPort_info.portlock);
var = set_btportLocked(&pPort_info);
//pthread_mutex_unlock(&pPort_info.portlock); if(var < 0)
{
LOGE("set_portLocked error!");
return -1;
} //在这里将获得输入的函数结构体指针,在后继数据上报的时候将通过这个函数结构体指针来实现
if(callBack != NULL)
pReceiveCmdPackage->callback = *callBack;
else
{
LOGE("BluetoothCallback struct is empty!");
return -1;
} //uart receive message thread and analyze it
sem_init(&pReceiveCmdPackage->uart_end, 0, 0);
pReceiveCmdPackage->uart_inited = true; //err = pthread_create(&pReceiveCmdPackage->thread_id, NULL, &BTuartDownloadData, (void *)pReceiveCmdPackage); //在这这里,通过callback的方式创建了一个线程,用于串口数据的读取和上报,这个线程是在VM中创建的一个java线程,一定要用这个,而不能用pthread_create,否则会出问题!
pReceiveCmdPackage->thread_id = callBack->bluetooth_thread("gocmd102_bluetooth", BTuartDownloadData, pReceiveCmdPackage); if (!pReceiveCmdPackage->thread_id)
{
LOGE("could not create bluetooth thread: %s", strerror(errno));
return -1;
} return fd;
}
当蓝牙打开时,上层app通过JNI调用到这个init函数完成串的初始,同时将JNI中调用java方法的函数结构体地址传入了进来,这个函数结构体如下:
typedef struct
{
size_t size;
void (*callIn_bt)(telephoneIn *callIn);
void (*state_bt)(int state);
void (*getVol_bt)(BtVol *vol);
void (*connect_bt)(matchDev *btDevice);
void (*match_bt)(matchDev *btDevice);
void (*downPHBook_bt)(phoneNumber *phoneNum);
void (*callOut_bt)(phoneNumber *dailNum);
pthread_t (* bluetooth_thread)(const char* name, void (*start)(void *), void* arg);
}BluetoothCallback,*pBluetoothCallback;
这个函数结构体里的回调函数在JNI中实现,我们来看看电话打入的时候上报电话号码的这个回调函数:
static void telephoneIn_callback(telephoneIn *callIn)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
jstring number = env->NewStringUTF(callIn->number); dbg(DBG_DEBUG," JNI telephoneIn_callback");
//调用java方法上报数据
env->CallVoidMethod(mBTCallbackObj,method_reportCallIn,callIn->Len,number); if(number)
env->DeleteLocalRef(number);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
这里mBTCallbackObj(jobject)是在java调用jni初始化的时候赋值的,应该是获得对应的java类,而method_reportCallIn(jmethodID)是获得的java中对应的java方法ID,如下:
static void android_location_BlueToothLocationProvider_class_init_native(JNIEnv* env, jclass clazz)
{
method_reportCallIn = env->GetMethodID(clazz, "telephoneCallIn", "(ILjava/lang/String;)V");
method_reportState = env->GetMethodID(clazz, "bluetoothState", "(I)V");
method_reportVol = env->GetMethodID(clazz, "reportVol", "(II)V");
method_reportConnect = env->GetMethodID(clazz,"reportConnect","(Ljava/lang/String;[I)V");
method_reportMatch = env->GetMethodID(clazz,"reportMatch","(ILjava/lang/String;[I)V");
method_reportPhoneBook = env->GetMethodID(clazz,"reportPhoneBook","(IILjava/lang/String;Ljava/lang/String;)V");
method_reportDailNum = env->GetMethodID(clazz,"reportDailNumber","(Ljava/lang/String;)V");
}
再来看看jni中创建java线程的回调函数:
static pthread_t bluetooth_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}
在相应的java类中电话打入的时候,号码上报的方法如下:
/**
* called from native code to update call in telephone number
*/
private void telephoneCallIn(int numberLen, String number)
{
if(DEBUG)
Log.v(TAG, "telephoneCallIn number: " + number); if(numberLen <= 0)
Log.e(TAG,"telpphone call in,but the phone number is null"); if(number != null)
{
// send an intent to notify there is a telephone call in.
Intent intent = new Intent(TELEPHONE_CALLIN_ACTION);
intent.putExtra(EXTRA_BT_PHONENUMBER, number);
mContext.sendBroadcast(intent);
} }
最后再来看看HAL中是如何通过这个回调函数上报数据的,当解析得到电话打入时,将会进入到如下黄色标注的这部分代码上报打入的电话号码:
static void processCharacterI(pBluetooth bt,const uuint8 *data)
{
const uuint8 *pdata = data; dbg(DBG_DEBUG,"processCharacterI : %s",pdata); switch(*pdata)
{
case 'D':
{
telephoneIn callIn; memset(&callIn,0,sizeof(telephoneIn)); callIn.Len = (*(++pdata)-0x30)*10;
callIn.Len += *(++pdata)-0x30;
callIn.number = ++pdata;
BLUETOOTH_CALLIN_CB(bt->callback,callIn);
}
break; case 'S':
BLUETOOTH_STATE_CB(bt->callback,uartInitOK);
break; case 'C':
{
phoneNumber CallOut;
uuint32 tmp=0; memset(&CallOut,0,sizeof(phoneNumber)); tmp = (*(++pdata)-0x30)*10;
tmp += *(++pdata)-0x30;
CallOut.nameLen = tmp; CallOut.number = ++pdata; BLUETOOTH_CALLOUT_CB(bt->callback,CallOut);
}
break; default:
LOGW(" Unknow command : I%s",pdata);
break;
}
}
其中BLUETOOTH_CALLIN_CB这个是如下定义的:
#define BLUETOOTH_CALLIN_CB(_cb,_in) \
if((_cb).callIn_bt){ \
(_cb).callIn_bt(&(_in)); \
}
这样完整的数据上报链路就已经打通了,当有相应的数据从串口发送出来时就会通过这套回调函数将数据上报至java方法中,最后在java方法中通过广播发给对应的监听者!
HAL中通过JNI调用java方法【转】的更多相关文章
- java native interface JNI 调用Java方法
在上一篇文章中介绍了JNI.以及java调用JNI.这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你能够创建Java对象,get.set 静态(static)和 实例(instanc ...
- Android Studio NDK开发-JNI调用Java方法
相对于NDK来说SDK里面有更多API可以调用,有时候我们在做NDK开发的时候,需要在JNI直接Java中的方法和变量,比如callback,系统信息等.... 如何在JNI中调用Java方法呢?就需 ...
- cocos2d-x中使用JNI的调用JAVA方法
用cocos2d-x公布Android项目时.都应该知道要用JAVA与C/C++进行交互时会涉及到JNI的操作(Java Native Interface).JNI是JAVA的一个通用接口.旨在本地化 ...
- 第5篇-调用Java方法后弹出栈帧及处理返回结果
在前一篇 第4篇-JVM终于开始调用Java主类的main()方法啦 介绍了通过callq调用entry point,不过我们并没有看完generate_call_stub()函数的实现.接下来在ge ...
- java 中使用ajax调用后台方法注意事项
java 中使用ajax调用后台方法注意事项,后台方法一定要加@ResponseBody jQuery.validator.addMethod("checkRuleName",fu ...
- init.rc文件中面启动c++程序,通过jni调用java实现
</pre><p>注:假设是自己的myself.jar包,还要修改例如以下:</p><p>target/product/core_base.mk PRO ...
- C++调用JAVA方法详解
C++调用JAVA方法详解 博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...
- C#调用Java方法(详细实例)
C#可以直接引用C++的DLL和转换JAVA写好的程序.最近由于工作原因接触这方面比较多,根据实际需求,我们通过一个具体例子把一个JAVA方法转换成可以由C#直接调用的DLL C#调用c++ C#调用 ...
- C#调用Java方法
C#调用Java方法(详细实例) 阅读目录 C#调用c++ C#调用JAVA方法 C#可以直接引用C++的DLL和转换JAVA写好的程序.最近由于工作原因接触这方面比较多,根据实际需求,我们通过一个具 ...
随机推荐
- cat 命令(转)
cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 1.命令格式: cat [选项] [文件] ...
- 基础拾掇之——http基础
基础拾掇之——http基础 http协议介绍 http:Hyper Text Transfer Protocol 超文本传输协议,是互联网应用最为广泛的一种网络协议,主要用于Web服务.通过计算机处理 ...
- [转帖]Speed-BI数据分析案例:2016年8月汽车销量排行榜
[转帖]Speed-BI数据分析案例:2016年8月汽车销量排行榜 据中国汽车工业协会统计分析,2016年8月,乘用车市场表现较好,当月销量环比和同比均呈较快增长.1-8月,乘用车销量总体呈稳定增长, ...
- Access 2003版数据库在Win7 64位系统下的不适应
使用ODBC连接不适应 使用microsoft.jet.4.0链接会出现“未在本地计算机上注册microsoft.jet.4.0” 应使用 Provider=Microsoft.ACE.OLEDB.1 ...
- javascript设计模式学习之七——迭代器模式
一.迭代器模式定义 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,并且不需要暴露该对象的内部表示. 在当前大部分语言中,都已经内置了迭代器模式.迭代器有内部迭代器和外部迭代器之分,一般现有语 ...
- Mysql主从库同步错误:1062 Error 'Duplicate entry '1438019'
mysql主从库同步错误:1062 Error 'Duplicate entry '1438019' for key 'PRIMARY'' on query mysql主从库在同步时会发生1062 L ...
- strip和stripe
- PostgreSQL Replication之第十一章 使用Skytools(1)
向您介绍了 Slony 之后,我们将介绍另外一种流行的复制工作.Skytools 是一个最初有 Skype 开发的软件包,它有多种用途.Skytools 不只是一个单一的程序,而且是一个工具与服务的集 ...
- java-语句
JAVA语句 1.顺序语句(用:结束)(一个分号也是一个语句)(多条语句形成符合语句) 2.分支语句(又称条件语句) 1. if 语句 例: int a=10 if(a>0) {System ...
- [转]数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
一.MySQL MySQL小型高可用架构 方案:MySQL双主.主从 + Keepalived主从自动切换 服务器资源:两台PC Server 优点:架构简单,节省资源 缺点:无法线性扩展,主从失 ...