JNI - Java + Linux [Resolvido]

6 respostas
D

Caros, é possível acessar uma shared library (.so) e a mesma efetuar uma chamada de volta de uma função java?
Segue código exemplo:

Acessando uma shared library da seguinte forma:

Código Java

public LoadLib() throws UnsatisfiedLinkError {
        System.loadLibrary("libTeste");
    }
    
    public native int Funcao1();
    
    public native boolean Funcao2();
    
    public native void Funcao3();

    public static void Testa(){
      System.out.println("Opa.. funcionandooooo!!!");
    }

Código C (.so)

#include <jni.h>  
#include "libTeste.h"  
#include <stdio.h>  

JNIEXPORT jint JNICALL Java_my_package_Funcao1(JNIEnv *env, jclass obj)  {
	
	int ret = 17;
	return (jint) ret;
}

JNIEXPORT jboolean JNICALL Java_my_package_Funcao2(JNIEnv *env, jobject obj) {
	Testa();
	return JNI_TRUE;
}

JNIEXPORT void JNICALL Java_my_package_Funcao3(JNIEnv *env, jobject obj) {
	printf("Dinho Fazendo um Teste na chamada da função externa\n");
     	return;
}

6 Respostas

J

é possivel mas não é simples assim!

Veja a resposta desse forum (no momento to sem tempo para reescrever seu programa):

É possível também criar um programa C ou C++, criar a jvm, e a partir do programa c/c++ chamar funções java, e do java funções nativas, etc… mais ou menos o que o javaw.exe faz… e o que alguns geradores de executaveis java fazem:
http://www.inonit.com/cygwin/jni/invocationApi/c.html

D

jmmenezes:
é possivel mas não é simples assim!

Veja a resposta desse forum (no momento to sem tempo para reescrever seu programa):

É possível também criar um programa C ou C++, criar a jvm, e a partir do programa c/c++ chamar funções java, e do java funções nativas, etc… mais ou menos o que o javaw.exe faz… e o que alguns geradores de executaveis java fazem:
http://www.inonit.com/cygwin/jni/invocationApi/c.html

Estou tentando com a função JNI_CreateJavaVM()
Mas não ta dando certo, o programa compila mas cai na condição de erro.

#include <jni.h>    
    #include "absoluta_web_AW_0001.h"    
    #include <stdio.h>    
    #include <string.h>  
    #include <stdio.h>  
    #include <stdlib.h>     /* General Utilities */  
      
        JavaVM *jvm;  
        JavaVMInitArgs vm_args;  
        JavaVMOption options[5];  
        jint res;  
        jclass cls;  
        jmethodID mid;  
        jstring jstr;  
        jobjectArray args;  
      
    JNIEXPORT jint JNICALL Java_Funcao1(JNIEnv *env, jclass obj)  {  
       int ret = 17;  
       return (jint) ret;  
    }  
      
    JNIEXPORT jboolean JNICALL Java_Funcao2(JNIEnv *env, jobject obj) {  
       return JNI_TRUE;  
    }  
      
      
    JNIEXPORT void JNICALL Java_Funcao3(JNIEnv *env, jobject obj) {  
       options[0].optionString = "-Djava.class.path=.";  
       vm_args.version = JNI_VERSION_1_6;  
       vm_args.options = options;  
       vm_args.nOptions = 1;  
       vm_args.ignoreUnrecognized = JNI_FALSE;  
         
       res = JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args);  
         
       if (res < 0) {  
          fprintf(stderr, "Can't create Java VM\n");  
          exit(1);  
       }  
         
       //cls = env->FindClass("ClasseJava()");  
            return;  
              
              
    }
J

Cara… se você esta rodando primeiro o programa Java… a JVM que esta rodando precisa ser obtida e não criada!
Você só cria a JVM quando o ponto de partida é o programa C/C++ que depois vai chamar o programa Java.

De uma olhada nesse post:

Provavelmente terá de fazer algo assim:

JNIEXPORT void JNICALL Java_MyPackage_MyClass_InitializeDLL
(JNIEnv *env, jobject obj, jobject callback)
{
      // Storing callback object in global variable.
    callBackObj = callback;

    env->GetJavaVM(&jvm);

    MyInstance = new MyClass();
    MyInstance ->SetAttachCallback(AttachCallBack, &callBackObj);
    MyInstance ->SetDetachCallback(DetachCallBack, &callBackObj);

      // Testing!
    jclass callBackCls = env->FindClass("MyPackage/MyClassCallBacks");
    jmethodID mid = env->GetMethodID(callBackCls, "attach", "(B)V");
    if (!mid)
        return ; /* method not found */
      //This call here works well
    env->CallVoidMethod(callBackObj, mid, 5);
}

Estou sem ambiente para testar aqui… se não conseguir resolver talvez consiga fazer este teste aqui…

D

jmmenezes:
Cara… se você esta rodando primeiro o programa Java… a JVM que esta rodando precisa ser obtida e não criada!
Você só cria a JVM quando o ponto de partida é o programa C/C++ que depois vai chamar o programa Java.

De uma olhada nesse post:

Provavelmente terá de fazer algo assim:

JNIEXPORT void JNICALL Java_MyPackage_MyClass_InitializeDLL
(JNIEnv *env, jobject obj, jobject callback)
{
      // Storing callback object in global variable.
    callBackObj = callback;

    env->GetJavaVM(&jvm);

    MyInstance = new MyClass();
    MyInstance ->SetAttachCallback(AttachCallBack, &callBackObj);
    MyInstance ->SetDetachCallback(DetachCallBack, &callBackObj);

      // Testing!
    jclass callBackCls = env->FindClass("MyPackage/MyClassCallBacks");
    jmethodID mid = env->GetMethodID(callBackCls, "attach", "(B)V");
    if (!mid)
        return ; /* method not found */
      //This call here works well
    env->CallVoidMethod(callBackObj, mid, 5);
}

Estou sem ambiente para testar aqui… se não conseguir resolver talvez consiga fazer este teste aqui…

jmmenezes, show de bola, este é mesmo o caminho. Olhei o link que me passou o cheguei no seguinte código, e carrega a class:

(*env)->GetJavaVM(env, &jvm);
	smartCallbackObject = (*env)->NewGlobalRef(env, obj);
	
	//MyInstance = new AW_0001();
	
	if (smartCallbackClass == NULL) {
		jclass localRefCls = (*env)->FindClass(env,"absoluta/web/AW_0001"); 
		if (localRefCls == NULL) {
			printf("Unable to create a JNI Java Class reference \n");
		} else {
			printf("CARREGOU! \n");
		}
		//Create a global reference for JNI Java class
		smartCallbackClass = (*env)->NewGlobalRef(env,localRefCls);
		
		//Delete the local reference as it is no longer needed
		(*env)->DeleteLocalRef(env, localRefCls);
		
		//Is the global reference created successfully?
		if (smartCallbackClass == NULL) {
			printf("Unable to create JNI Java class reference \n");
		}       
	}

Agora não sei como chamar um método dentro da classe.

vlwwww

D

:smiley:
Perfect. Seguindo as dicas do nosso amigo jmmenezes e fuçando em um e outro link chegamos no código funcional.

A idéia dessa integração, é mesclar o meu código com vários arquivos .so tornando-o mais seguro contra engenharia reversa, ok?

Aqui o código JAVA

public class MinhaClasse {
    
    public MinhaClasse() throws UnsatisfiedLinkError {
        System.loadLibrary("MinhaClasse"); // Aqui carrega a lib .so
    }
    
    public native void Funcao3(); // Se encarrega de chamar o método Testa() abaixo. 
    
    public void Testar(){
    	    System.out.println("Opa.. funcionandooooo!!!");
    }
    
    
}

E aqui o código C

#include <jni.h>  
#include "package_MinhaClasse.h"  

jclass smartCallbackClass;
static JavaVM *jvm = NULL;
static jobject smartCallbackObject = NULL;


JNIEXPORT void JNICALL Java_package_Funcao3(JNIEnv *env, jobject obj, jobject callback) {
	(*env)->GetJavaVM(env, &jvm);
	smartCallbackObject = (*env)->NewGlobalRef(env, obj);
	
	if (smartCallbackClass == NULL) {
		jclass localRefCls = (*env)->FindClass(env,"package/MinhaClasse"); 
		if (localRefCls == NULL) {
			printf("Unable to create a JNI Java Class reference \n");
		} else {
			printf("CARREGOU! \n");
		}
		//Create a global reference for JNI Java class
		smartCallbackClass = (*env)->NewGlobalRef(env,localRefCls);
		
		// Esse trecho abaixo faz a chamada do método Testar() em MinhaClasse()
		jclass cls = (*env)->GetObjectClass(env, smartCallbackObject);
		jmethodID mid = (*env)->GetMethodID(env, cls, "Testar", "()V");
		(*env)->CallVoidMethod(env, smartCallbackObject, mid);
		(*jvm)->DetachCurrentThread(jvm);	
		
		
		//Delete the local reference as it is no longer needed
		(*env)->DeleteLocalRef(env, localRefCls);
		
		//Is the global reference created successfully?
		if (smartCallbackClass == NULL) {
			printf("Unable to create JNI Java class reference \n");
		}       
	}
     	return;
}
J

Legal cara! Muito bom que deu certo! E legal ter postado a solução completa também!
Coloca o tópico como resolvido, desta forma se algum outro colega tiver essa mesma duvida, sabe que aqui terá a solução.

Criado 19 de março de 2013
Ultima resposta 19 de mar. de 2013
Respostas 6
Participantes 2