How to fix crash when call env->SetStaticIntField(cls, jfid, 0) method - android-ndk

I called env->SetStaticIntField(cls, jfid, 0); app crashed .
addr2line tool found this:
/usr/local/google/buildbot/src/android/ndk-release-r19/external/libcxx/../../external/libcxxabi/src/cxa_demangle.cpp:2125
My application is using cmake_minimum_required(VERSION 3.4.1) and cppFlags "-std=c++14"
c++ method like this :
JNIEXPORT jint JNICALL
Java_zhumu_xiaot_com_ndkdemo_MainActivity_operateStaticInt(JNIEnv *env,
jobject instance) {
jclass cls = env->GetObjectClass(instance);
jfieldID jfid = env->GetStaticFieldID(cls, "staticint", "I");
jint jsataticint = env->GetStaticIntField(cls, jfid);
env->SetStaticIntField(cls, jfid, 80);
}

Related

JNI: Invoking CallVoidMethod from thread crashes

For some reason, when I try to access a java object (which persists throughout the entire program, BTW) from a thread, the program crashes. Here's a boiled down example to demonstrate the problem:
#include <jni.h>
#include <pthread.h>
pthread_t thread;
jobject object;
JavaVM* jvm;
/*
Our thread function:
*/
void* run( void* );
extern "C" void Java_com_Program_Initialize( JNIEnv* jnv, jobject caller )
{
object = caller;
jnv->GetJavaVM( &jvm );
/*
Before launching our thread, this works just fine:
*/
jnv->CallVoidMethod( object, jnv->GetMethodID( jnv->GetObjectClass( object ), "foo", "()V" ) );
pthread_create( &thread, NULL, run, NULL );
}
void* run( void* )
{
JNIEnv* jnv;
jvm->AttachCurrentThread( &jnv, NULL );
/*
Within the context of our thread however, this crashes:
*/
jnv->CallVoidMethod( object, jnv->GetMethodID( jnv->GetObjectClass( object ), "foo", "()V" ) );
jvm->DetachCurrentThread( );
return NULL;
}
Any ideas as to what's going wrong?
Okay, the problem seemed to be a missing NewGlobalRef call. This version works:
#include <jni.h>
#include <pthread.h>
pthread_t thread;
jobject object;
JavaVM* jvm;
/*
Our thread function:
*/
void* run( void* );
extern "C" void Java_com_Program_Initialize( JNIEnv* jnv, jobject caller )
{
object = jnv->NewGlobalRef( caller );
jnv->GetJavaVM( &jvm );
pthread_create( &thread, NULL, run, NULL );
}
void* run( void* )
{
JNIEnv* jnv;
jvm->AttachCurrentThread( &jnv, NULL );
jnv->CallVoidMethod( object, jnv->GetMethodID( jnv->GetObjectClass( object ), "foo", "()V" ) );
jnv->DeleteGlobalRef( object );
jvm->DetachCurrentThread( );
return NULL;
}
I'd like to suggest you to try to find a way to post the invocation to main thread.
Since the entire process from "AttachCurrentThread" to "DetachCurrentThread" is not locked, the main thread may re"AttachCurrentThread", in some case, before the "run" finished. Thus there would still be issues.

Calling JNI Native functions from other native functions

I am implementing an android app using JNI ,
I have some JNI functions ,
#include <stdio.h>
#include <jni.h>
// other header files
JNIEXPORT jint JNICALL Java_com_example_projectpmic_NativeLib_get_1clock_1status
(JNIEnv *env, jobject obj, jint v)
{ / will do something
pthread_t native_thread ;
pthread_create(&native_thread,NULL,native_thread_funtion,NULL) ;
}
JNIEXPORT jint JNICALL Java_com_example_projectpmic_NativeLib_get_name
(JNIEnv *env, jobject obj, jint v)
{ / will do something
}
void *native_thread_function(void* args)
{
/*I want to call the above get_name() function in this thread function ,
// How to do that ? */
}
Note : These two functions are in same .c file
To call a JNI method from an arbitrary native method you need a JNIEnv pointer, and the only place to get one is from AttachCurrentThread().

error LNK2001: unresolved external symbol __imp__Py_InitModule4

I'm trying to extend Python with C++. I'm using Visual C++ 2008 and Python 2.7. I have had a lot of problems building the .dll file, and finally when it seemed to be everything correct, I can't stop getting this error:
error LNK2001: unresolved external symbol _imp_Py_InitModule4
I know it isn't a linker error because I had this error before (it gave me the error but with all kind of Py_... functions) and I had resolved that.
I don't know if this is an important data but I have build python27_d.dll with VC++ 2008 too.
This is the code:
#include "Python.h"
#include <windows.h>
#include <string.h>
#include <tchar.h>
#include <stdlib.h>
#include <Aclapi.h>
struct file_perms {
char user_domain[2050];
unsigned long user_mask;
};
void lookup_sid ( ACCESS_ALLOWED_ACE* pACE, char user_domain[] ) {
char username[1024]="";
char domain[1024]="";
ULONG len_username = sizeof(username);
ULONG len_domain = sizeof(domain);
PSID pSID =(PSID)(&(pACE->SidStart));
SID_NAME_USE sid_name_use;
LPWSTR username1 = reinterpret_cast<LPWSTR>( username );
LPWSTR domain1 = reinterpret_cast<LPWSTR>( domain );
if (!LookupAccountSid(NULL, pSID, username1, &len_username, domain1, &len_domain, &sid_name_use)){
strcpy(user_domain, "unknown");
} else {
strcat(user_domain,domain);
strcat(user_domain,"\\");
strcat(user_domain,username);
}
}
void acl_info( PACL pACL, ULONG AceCount, file_perms fp[]){
for (ULONG acl_index = 0;acl_index < AceCount;acl_index++){
ACCESS_ALLOWED_ACE* pACE;
if (GetAce(pACL, acl_index, (PVOID*)&pACE))
{
char user_domain[2050]="";
lookup_sid(pACE,user_domain);
strcpy(fp[acl_index].user_domain,user_domain);
fp[acl_index].user_mask=(ULONG)pACE->Mask;
}
}
}
static PyObject *get_perms(PyObject *self, PyObject *args)
{
PyObject *py_perms = PyDict_New();
//get file or directory name
char *file;
if (!PyArg_ParseTuple(args, "s", &file))
return NULL;
//setup security code
PSECURITY_DESCRIPTOR pSD;
PACL pDACL;
//GetNamedSecurityInfo() will give you the DACL when you ask for
//DACL_SECURITY_INFORMATION. At this point, you have SIDs in the ACEs contained in the DACL.
LPWSTR file1 = reinterpret_cast<LPWSTR>( file );
ULONG result = GetNamedSecurityInfo(file1,SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
&pDACL, NULL, &pSD);
if (result != ERROR_SUCCESS){ return NULL;}
if (result == ERROR_SUCCESS){
ACL_SIZE_INFORMATION aclSize = {0};
if(pDACL != NULL){
if(!GetAclInformation(pDACL, &aclSize, sizeof(aclSize),
AclSizeInformation)){
return NULL;
}
}
file_perms *fp = new file_perms[aclSize.AceCount];
acl_info(pDACL, aclSize.AceCount, fp );
//Dict
for (ULONG i=0;i<sizeof(fp);i++){
PyObject *domain = Py_BuildValue("s",fp[i].user_domain);
PyObject *user = Py_BuildValue("s",fp[i].user_mask);
PyDict_SetItem(py_perms,domain,user);
}
}
return py_perms;
};
static PyMethodDef fileperm_methods[] = {
{ "get_perms", get_perms, METH_VARARGS, "Execute a shell command." },
{ NULL, NULL, 0, NULL }
};
extern "C"
__declspec(dllexport)
void init_fileperm(void)
{
PyObject *m=Py_InitModule("fileperm",fileperm_methods);
return;
}
I'm working in Windows 7 64bits.
I know that Py_InitModule is deprecated for Python 3 but I'm working in Python27 (2.7.3 ).
Does someone know why I get this error?
Thanks!
I had the same problem.
If you're compiling a 64-bit pyd, make sure python27.lib is also 64-bit (same goes for compiling a 32-bit pyd with a 32-bit python27.lib).

Sharing a JavaVM* across threads in Android NDK

I want to call Java class methods from a cpp file that receives call backs from another executable.
To achieve this, I have retrieved a JavaVM pointer using the android::AndroidRuntime::getJavaVM() method in the .cpp file that directly receives JNI method calls. I am sharing this JavaVM pointer via the constructor to the eventual .cpp file where I call required Java methods as follows:
/* All the required objects(JNIEnv*,jclass,jmethodID,etc) are appropriately declared. */
**JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL);
clazz = env->FindClass("com/skype/ref/NativeCodeCaller");
readFromAudioRecord = env->GetStaticMethodID(clazz, "readFromAudioRecord", "([B)I");
writeToAudioTrack = env->GetStaticMethodID(clazz, "writeToAudioTrack", "([B)I");**
However, I get a SIGSEGV fault running this code.
According to the JNI documentation this seems to be the appropriate way to obtain JNIEnv in arbitary contexts: http://java.sun.com/docs/books/jni/html/other.html#26206
Any help in this regard will be appreciated.
Regards,
Neeraj
Global references will NOT prevent a segmentation fault in a new thread if you try to use a JNIEnv or JavaVM reference without attaching the thread to the VM. You were doing it properly the first time around, Mārtiņš Možeiko is mistaken in implying that there was something wrong with what you were doing.
Don't remove it, just learn how to use it. That guy doesn't know what he's talking about, if it's in jni.h you can be pretty sure it's not going anywhere. The reason it's not documented is probably because it's ridiculously self explanatory. You don't need to create GlobalReference objects or anything either, just do something like this:
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#include <linux/threads.h>
#include <pthread.h>
#define LOG_TAG "[NDK]"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static pthread_mutex_t thread_mutex;
static pthread_t thread;
static JNIEnv* jniENV;
void *threadLoop()
{
int exiting;
JavaVM* jvm;
int gotVM = (*jniENV)->GetJavaVM(jniENV,&jvm);
LOGI("Got JVM: %s", (gotVM ? "false" : "true") );
jclass javaClass;
jmethodID javaMethodId;
int attached = (*jvm)->AttachCurrentThread(jvm, &jniENV,NULL);
if(attached>0)
{
LOGE("Failed to attach thread to JavaVM");
exiting = 1;
}
else{
javaClass= (*jniENV)->FindClass(jniENV, "com/justinbuser/nativecore/NativeThread");
javaMethodId= (*jniENV)->GetStaticMethodID(jniENV, javaClass, "javaMethodName", "()V");
}
while(!exiting)
{
pthread_mutex_lock(&thread_mutex);
(*jniENV)->CallStaticVoidMethod(jniENV, javaClass, javaMethodId);
pthread_mutex_unlock(&thread_mutex);
}
LOGE("Thread Loop Exiting");
void* retval;
pthread_exit(retval);
return retval;
}
void start_thread(){
if(thread < 1)
{
if(pthread_mutex_init(&thread_mutex, NULL) != 0)
{
LOGE( "Error initing mutex" );
}
if(pthread_create(&thread, NULL, threadLoop, NULL) == 0)
{
LOGI( "Started thread#: %d", thread);
if(pthread_detach(thread)!=0)
{
LOGE( "Error detaching thread" );
}
}
else
{
LOGE( "Error starting thread" );
}
}
}
JNIEXPORT void JNICALL
Java_com_justinbuser_nativecore_NativeMethods_startThread(JNIEnv * env, jobject this){
jniENV = env;
start_thread();
}
Solved the problem. The segmentation fault was because I could not retrieve a jclass object from the JNIEnv object retrieved from the shared jvm pointer.
I propogated a Global reference jclass object alongwith the jvm and the problem was solved.
Thanks for your help Mārtiņš Možeiko!..
Regards,
Neeraj

jint problem with NDK

I'm trying to make my first native function with NDK and I'm in trouble with very basic stuff.
Please consider the following c code:
#include <jni.h>
#include <string.h>
JNIEXPORT jint JNICALL Java_eu_elevelcbt_sm_YCrCbUtils_toARGB(
JNIEnv* env, jbyteArray src, jintArray out, jint width, jint height){
jbyte *c_src = (*env)->GetByteArrayElements(env, src, NULL);
jint *c_out = (*env)->GetDirectBufferAddress(env, out);
if (c_out==NULL)
return -1;
int length = width * height;
int co;
unsigned int color;
for (co=0; co<length; co++) {
color = c_src[co] & 0xFF;
color = 0xFF000000 | (color<<16) | (color<<8) | color;
c_out[co] = color;
}
(*env)->ReleaseByteArrayElements(env, src, c_src, 0);
return 0;
}
JNIEXPORT jint JNICALL Java_eu_elevelcbt_sm_YCrCbUtils_sum(jint a, jint b){
return a+b;
}
and the following Java class:
public class YCrCbUtils {
public native int toARGB(byte[] src, int[] out, final int width, final int height);
public native int sum(int a, int b);
static {
System.loadLibrary("yuv");
}
}
Problem 1: If I call the second function
Log.v("DBG", "sum is: " + new YCrCbUtils().sum(10, 5));
This is what I get: "sum is 1079199776" !!!! WHY?!??!? :(
If I try calling first function like this:
int[] colors = new int[size.width * size.height]; // where width=800 and height=480
new YCrCbUtils().toARGB(data, colors, size.width, size.height); // data is a byte[]
I get a SIGSEGV error...
HELP please!!!
PS: my dev environment is MAC OSX Snow Leopard, NDK-r5b. My runtime env is Nexus One 2.3.3
...ok I'm stupid...
My methods signatures were WRONG... They always must have "JNIEnv* env, jobject obj" as first two members... well I spend an afternoon on this but the good thing is that now I'll never forget it!
Also, on my first method I had to change
jint *c_out = (*env)->GetDirectBufferAddress(env, out);
with
jint *c_out = (*env)->GetIntArrayElements(env, out, NULL);
as the previous one was returning a NULL pointer

Resources