如果调用以下函数,应用程序崩溃:
void on_log(JavaVM* vm, int level, const char *data)
{
printOnAndroid(level, data);
pthread_t loggerThread;
pthread_create(&loggerThread, NULL, attachThreadToJavaVMAndPrint, data);
pthread_join(loggerThread, NULL);
}
void attachThreadToJavaVMAndPrint(JavaVM* vm, const char *data)
{
int isThreadAttached = attachJNIEnvToThread(vm);
if (isThreadAttached == 1)
{
JNIEnv* env;
(*vm)->GetEnv(vm, &env, APP_JNI_VERSION);
jclass thisClass = (*env)->GetObjectClass(env, _loggerObject);
jmethodID methodId = (*env)->GetMethodID(env, thisClass, "logFromC","(Ljava/lang/String;)V");
if (methodId != NULL)
{
jstring message = (*env)->NewStringUTF(env, data);
(*env)->CallVoidMethod(env, _loggerObject, methodId, message);
}
(*vm)->DetachCurrentThread(vm);
}
}
void printOnAndroid(int level, const char* data)
{
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "XXXX %i, data %s", level, data);
}
int attachJNIEnvToThread(JavaVM* vm)
{
JNIEnv* env;
JavaVMAttachArgs args;
args.version = APP_JNI_VERSION;
args.name = NULL;
args.group = NULL;
if ((*vm)->GetEnv(vm, &env, APP_JNI_VERSION) == JNI_EDETACHED)
{
jint attachResponse = (*vm)->AttachCurrentThread(vm, &env, &args);
if ((*vm)->GetEnv(vm, &env, APP_JNI_VERSION) != JNI_OK)
{
return 0;
}
}
return 1;
}
有一个宏:
#define APP_JNI_VERSION JNI_VERSION_1_2
根据日志,调用attachJNIEnvToThread(..)时会出现崩溃
编辑:
它在linux上运行成功..所以可能有一些我不知道的特定于Android的东西。
编辑2:
更改了以下内容的签名:
void * attachThreadToJavaVMAndPrint(void* dataArg)
{
JavaVM* vm = _vm;
const char* data = (const char *)dataArg;
int isThreadAttached = attachJNIEnvToThread(vm);
if (isThreadAttached == 1)
{
JNIEnv* env;
(*vm)->GetEnv(vm, &env, APP_JNI_VERSION);
jclass thisClass = (*env)->GetObjectClass(env, _loggerObject);
jmethodID methodId = (*env)->GetMethodID(env, thisClass, "logFromC","(Ljava/lang/String;)V");
if (methodId != NULL)
{
jstring message = (*env)->NewStringUTF(env, data);
(*env)->CallVoidMethod(env, _loggerObject, methodId, message);
}
(*vm)->DetachCurrentThread(vm);
}
return 0;
}
这会稍微改变日志,崩溃在attachThreadToJavaAndPrint(..)
编辑3:
这已经解决了。最后的更改包括编辑2 + java代码中的一些更改(此处不可见(其中有错误))..
答案 0 :(得分:1)
首先,确保void on_log(JavaVM* vm, int level, const char *data)
中的参数vm正确。我将vm保存为JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
中的全局变量,我的代码可以工作:
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
g_vm = vm;
}
在线程函数
中{
ret = g_vm->AttachCurrentThread( (JNIEnv **) &env, NULL);
}
答案 1 :(得分:1)
代码中存在问题的地方是创建线程时。线程函数采用 ONE 指针,而不是两个。
因此,你可以给它VM*
或data
,或将它们包装成某种结构。
包装示例:
struct params
{
JavaVM *vm;
char *data;
};
void on_log(JavaVM* vm, int level, const char *data)
{
struct params params = {vm, data};
printOnAndroid(level, data);
pthread_t loggerThread;
pthread_create(&loggerThread, NULL, attachThreadToJavaVMAndPrint, ¶ms);
pthread_join(loggerThread, NULL);
}
void * attachThreadToJavaVMAndPrint(void* arg)
{
struct params *params = arg;
JavaVM* vm = params->vm;
const char* data = params->data;
...
第二个问题在于线程附件:在连接到线程之前你不能得到JNIEnv:
int attachJNIEnvToThread(JavaVM* vm)
{
JNIEnv* env;
return (*vm)->AttachCurrentThread(vm, &env, NULL) ? 1 : 0;
}