如何在android的jni线程中实现回调

Python040

如何在android的jni线程中实现回调,第1张

JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。

其中一种在Android系统的解决方案是:

把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。

假设有c++函数:

[cpp] view plaincopy

void *thread_entry(void *args)

{

while(1)

{

printf("thread running...\n")

sleep(1)

}

}

void init()

{

pthread_t thread

pthread_create(&thread,NULL,thread_entry,(void *)NULL)

}

init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive:

[cpp] view plaincopy

public void Receive(char buffer[],int length){

String msg = new String(buffer)

msg = "received from jni callback:" + msg

Log.d("Test", msg)

}

首先在c++中定义回调函数指针:

[cpp] view plaincopy

//test.h

#include <pthread.h>

//function type for receiving data from native

typedef void (*ReceiveCallback)(unsigned char *buf, int len)

/** Callback for creating a thread that can call into the Java framework code.

* This must be used to create any threads that report events up to the framework.

*/

typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg)

typedef struct{

ReceiveCallback recv_cb

CreateThreadCallback create_thread_cb

}Callback

再修改c++中的init和thread_entry函数:

[cpp] view plaincopy

//test.c

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <sys/wait.h>

#include <unistd.h>

#include "test.h"

void *thread_entry(void *args)

{

char *str = "i'm happy now"

Callback cb = NULL

int len

if(args != NULL){

cb = (Callback *)args

}

len = strlen(str)

while(1)

{

printf("thread running...\n")

//invoke callback method to java

if(cb != NULL &&cb->recv_cb != NULL){

cb->recv_cb((unsigned char*)str, len)

}

sleep(1)

}

}

void init(Callback *cb)

{

pthread_t thread

//pthread_create(&thread,NULL,thread_entry,(void *)NULL)

if(cb != NULL &&cb->create_thread_cb != NULL)

{

cb->create_thread_cb("thread",thread_entry,(void *)cb)

}

}

然后在jni中实现回调函数,以及其他实现:

[cpp] view plaincopy

//jni_test.c

#include <stdlib.h>

#include <malloc.h>

#include <jni.h>

#include <JNIHelp.h>

#include "android_runtime/AndroidRuntime.h"

#include "test.h"

#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"

using namespace android

static jobject mCallbacksObj = NULL

static jmethodID method_receive

static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {

if (env->ExceptionCheck()) {

LOGE("An exception was thrown by callback '%s'.", methodName)

LOGE_EX(env)

env->ExceptionClear()

}

}

static void receive_callback(unsigned char *buf, int len)

{

int i

JNIEnv* env = AndroidRuntime::getJNIEnv()

jcharArray array = env->NewCharArray(len)

jchar *pArray

if(array == NULL){

LOGE("receive_callback: NewCharArray error.")

return

}

pArray = (jchar*)calloc(len, sizeof(jchar))

if(pArray == NULL){

LOGE("receive_callback: calloc error.")

return

}

//copy buffer to jchar array

for(i = 0i <leni++)

{

*(pArray + i) = *(buf + i)

}

//copy buffer to jcharArray

env->SetCharArrayRegion(array,0,len,pArray)

//invoke java callback method

env->CallVoidMethod(mCallbacksObj, method_receive,array,len)

//release resource

env->DeleteLocalRef(array)

free(pArray)

pArray = NULL

checkAndClearExceptionFromCallback(env, __FUNCTION__)

}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)

{

return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg)

}

static Callback mCallbacks = {

receive_callback,

create_thread_callback

}

static void jni_class_init_native

(JNIEnv* env, jclass clazz)

{

method_receive = env->GetMethodID(clazz, "Receive", "([CI)V")

}

static int jni_init

(JNIEnv *env, jobject obj)

{

if (!mCallbacksObj)

mCallbacksObj = env->NewGlobalRef(obj)

return init(&mCallbacks)

}

static const JNINativeMethod gMethods[] = {

{ "class_init_native", "()V", (void *)jni_class_init_native },

{ "native_init","()I", (void *)jni_init },

}

static int registerMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME

jclass clazz

/* look up the class */

clazz = env->FindClass(kClassName)

if (clazz == NULL) {

LOGE("Can't find class %s/n", kClassName)

return -1

}

/* register all the methods */

if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)

{

LOGE("Failed registering methods for %s/n", kClassName)

return -1

}

/* fill out the rest of the ID cache */

return 0

}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {

JNIEnv* env = NULL

jint result = -1

LOGI("Radio JNI_OnLoad")

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

LOGE("ERROR: GetEnv failed/n")

goto fail

}

if(env == NULL){

goto fail

}

if (registerMethods(env) != 0) {

LOGE("ERROR: PlatformLibrary native registration failed/n")

goto fail

}

/* success -- return valid version number */

result = JNI_VERSION_1_4

fail:

return result

}

jni的Android.mk文件中共享库设置为:

[cpp] view plaincopy

LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最后再实现Java中的Test类:

[java] view plaincopy

//com.tonny.Test.java

public class Test {

static{

try {

System.loadLibrary("test")

class_init_native()

} catch(UnsatisfiedLinkError ule){

System.err.println("WARNING: Could not load library libtest.so!")

}

}

public int initialize() {

return native_radio_init()

}

public void Receive(char buffer[],int length){

String msg = new String(buffer)

msg = "received from jni callback" + msg

Log.d("Test", msg)

}

protected static native void class_init_native()

protected native int native_init()

}

一、alps/packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java

processAnswerCall

这个方法就是接听电话 我们来往上走 还是

alps/packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java

原来是jni回调java。

alps/packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

alps/packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

alps/packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

alps/packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

alps/packages/apps/Bluetooth/jni/com_android_bluetooth_hfp.cpp

alps/system/bt/btif/src/btif_hf.c

alps/system/bt/btif/src/btif_hf.c

alps/system/bt/btif/src/btif_hf.c

alps/hardware/libhardware/include/hardware/bt_hf.h

好了 跟踪完了

logcat | grep "AT cmd"

第一个是接听 第二个是挂断

再往下跟

p_cmd_cback

alps/system/bt/bta/ag/bta_ag_at.c

bta_ag_process_at

alps/system/bt/bta/ag/bta_ag_at.c

system/bt/bta/ag/bta_ag_act.c