JNI wrapped DLL only works when called from the default package - java

I have been given a DLL and a JNI wrapper which are used to access a business card scanner.
So far I have only been able to call the API when all classes are in the default package. When I try to move classes to other packages I get an UnsatisfiedLinkError.
I have had no experience of JNI up until now and wonder if I need to rewrite the wrapper of if I can organise the project in a different way. What I cannot do is to use the default package as this would mean putting all my classes there.
The wrapper looks something like this:
public final class Wrapper {
private native int CRTK_Init(int[] lphRTK);
private int m_hRTK;
private int m_hRTKDB;
static
{
System.loadLibrary("crtk_jni");
}
public Wrapper() {
m_hRTKDB = 0;
int[] pRTK = new int[1];
CRTK_Init(pRTK); // UnsatisfiedLinkError here
m_hRTK = pRTK[0];
}
}

The thing with JNI is that the fully qualified class name of the class containing the native methods is tightly coupled to the method-signature of the native (C-)functions.
The C-signature must be something like
JNIEXPORT jobject JNICALL Java_packageName_className_methodName(JNIEnv * env, jclass parameter)
Renaming the class or moving it to another package would change the expected function-name and result in an UnsatisfiedLinkError.
So what can you do?
Unless you have access to the native sources to change the function-names all classes that come as a bundle together with the dll must remain in the default-package, all your own classes can go where you want to have them.
Getting a JNI-package that has its native methods in the default-package is considered poor style and does not bode well for the quality of the received software. And be prepared for further trouble than can come from using the default package, AFAIR e.g. tomcat had (has?) problems with those.

Related

How to know dynamically if the loaded class is application class?

I am in a situation that I want to do some rewriting on loaded,i.e., currently running application class. I do not want to rewrite loaded library class. Thus I need to sort of filter the rewriting based either on the type of the class, being application or none application class, or another way I could do it is by checking the ClassLoader and see if it is of Application Class type.
To give some context let's assume I have the following code
URLClassLoader urlcl = new URLClassLoader(cp);
Class c = urlcl.loadClass(_className);
Assuming that _className is the current running class, that was intercepted by a listener, how can I know if this class c is an application class or not?
Much appreciated!
I'm not entirely sure of what do you mean by application class, but those hints still might be helpful.
You can simply check if one class is subtype of another with:
public static boolean is1stSubTypeOf2nd(Class clazz1, Class clazz2) {
return clazz2.isAssignableFrom(clazz1);
}
If you would like to check if the class belongs to some package (to check if it is the class from standard API, third party library or not), you can use:
public static boolean isInPackage(Class clazz, String packageName) {
return clazz.getPackageName().contains(packageName);
}
Further the standard API is able to provide you an info about all super classes of given class.

Loading a static void C function via AndroidfromJNI another Package

I am trying some things out with JNI and by that I found the following problem:
If I want to use a native function in Java I load the needed lib, in which the needed function is stored, via
static{
System.loadLibrary("lib");
}
and use
native private static int calculate(byte[] numberArray);
to declare the native method in the java file. During the program itself I can use this function to calculate something with:
int result = calculate(array);
This works only if I compiled the shared object with the header-file created by javah so that each function is named on c side as:
static void Java_com_packagename_File_calculate(const void* array, void* result){
code[...]
}
If I delete the reference in the java code ("native [...] calculate[...]")to this c function; is there any possibility to access / execute the still existing c-code via java (of course without editing the exisiting file ;-)) for example via reflections or inheritance? Or is there something possible like:
public class NewClass{
public int nativeCheater(){
System.loadLibrary("lib");
native private static int Java_com_packagename_File_calculate;
}
}
It is important that I want to use a whole new class without any relations to the prior used package com.packagename.(File).
Thanks in advance :-)
No, but you can create a new class with same package and class name and access the same native method. The new class can declare this method public.
An alternative is to use dynamic binding via Jni_OnLoad() and RegisterNatives(). This way, your native implementations may bind to any Java class, or even more than one.
But if you have access neither to the Java class nor to the native source, you can always create your own native method, in your own class, and inside your C explicitly call the original:
static void Java_com_mypackagename_File_calculate(const void* array, void* result) {
Java_com_packagename_File_calculate(array, result);
}

How can I conveniently wrap a caller-sensitive API?

Certain Java APIs are caller-sensitive. One (woefully underdocumented IMO) example is System.load(), which loads some JNI code into the caller's ClassLoader only.
I have a wrapper that looks roughly like JniUtils.loadLibrary("nameoflibrary"). It finds the appropriate library for the current architecture, extracts it out of the JAR, and passes it to System.load(). But I just ran into a case where the caller of JniUtils.loadLibrary wasn't in the same ClassLoader as Jni itself. That caused the library to get loaded into the wrong ClassLoader, resulting in UnsatisfiedLinkError once the native methods got called.
Without relying on JVM internals like sun.reflect.Reflection.getCallerClass(), is there a way to work around this issue? My current idea is to change the wrapper like this:
public class JniUtils {
public static void loadLibrary(String libraryName, MethodHandles.Lookup lookup);
}
which can be called like this:
public class NeedsJni {
static {
JniUtils.loadLibrary("nameoflibrary", MethodHandles.lookup());
}
}
Using the Lookup to resolve and call the System.load() method should preserve NeedsJni as the caller.
Is there a better workaround?
Depending on the complexity of your problem, this may or may not be applicable.
Under a context without reflection, it's hard for standard java code to replicate caller-sensitivity, even more so to "emulate" it to a caller-sensitive function. Even if it were done the code, in my opinion, would be incredibly obscure or would deal with deep dark language features that I would consider unnecessary.
The fundamental problem you have here is that System.load() is caller sensitive and you're trying to build your own "enhanced" System.load() by doing a bunch of other tasks prior to calling System.load() yourself. Why not leave System.load() exactly where it was when you started?
Rather than trying to replace the functionality of System.load(), complement it with your JniUtils class. Write a JniUtils.fetchLibrary() which returns a string in which the original caller can load from. Even better, return a custom object Library (or other names to that equivalent) containing a method that allows the retrieval of the string that should be passed to System.load(). From this, the call to load() can come from the point of need whilst your caller-insensitive code can do all the initialization separately.
Something to this example would be good:
public class JniUtils {
private static final HashMap<String, JniLibrary> cachedLibs = new HashMap<>();
public static JniLibrary fetchLibrary(String libname){
// Check cache for library
if(cachedLibs.containsKey(libname)){
return cachedLibs.get(libname);
}else{
JniLibrary lib = preloadLibrary(libname);
if(lib != null){
cachedLibs.put(libname, lib);
}
return lib;
}
}
/**
* Internal logic to prepare and generate a library instance
*
* #return JNI library on success, null on failure.
*/
private static JniLibrary preloadLibrary(String libname){
// Find lib
// Extract
// Get path
// Construct JniLibrary instance
// Return library as appropriate
}
/**
* Class representing a loadable JniLibrary
*/
public class JniLibrary{
public String getLibraryPath();
// Other potentially useful methods
}
}
public class NeedsJni {
static {
JniLibrary lib = JniUtils.fetchLibrary("nameoflibrary");
if(lib != null){
System.load(lib.getLibraryPath()); // Caller-sensitivity respected
}else{
// Well.... this is awkward.
}
}
}
not only does that solve the caller-sensitivity issue, the additional caching prevents additional extraction/architecture lookup and eventual failure (since the file you extract to would probably have been in use), allowing multiple calls to System.load() from different classes under different classloaders as appropriate.
The countercase to this approach is that if there is important code that has to be executed right after System.load() in your custom loadLibrary() method (suddenly, you wished java would have some sort of "OnLibraryLoad" event). In that case, perhaps add a method to run the post-load code within your main JniUtils class or the returned Library class (it's more ugly I know, but with clear documentation, it can't be that bad).
Consider defining an abstract class which has to be provided if the classpath is going to be incompatible. This provides "caller sensitivity" as the caller has to provide the implementation, thus providing the necessary context.
public class JniUtils {
public static void loadLibrary(String libraryName, Delegate delegate) {
//use delegate's provided classloader to find the native library from within the jar and extract
//ask the delegate to load the extracted library
}
public static abstract class Delegate {
/**
* #return The specific ClassLoader instance to use to find the native resource. If returning null, the ClassLoader of JniUtils will be used.
*/
public ClassLoader getLibraryClassLoader() {
return getClass().getClassLoader();
}
/**
* <p>
* The callback method which will be called once the native library's name has been
* resolved. This MUST be implemented by the subclass, so that it resolves as the "caller"
* class for {#link System#loadLibrary(String)}.
* </p>
*
* #param libraryName The name of the library to load.
*/
public abstract void loadLibrary(String libraryName);
}
}

Android NDK - Include a c++ header in a different header?

I have an Ability.h file that is dependent on an Effect.h file.
I need to use javah to generate my header, but I'm unable to define an Effect dependency in my Ability.java class from which I'd like the c++ header to be generated.
Example:
public class Ability {
static {
System.loadLibrary("com_test_Effect");
System.loadLibrary("com_test_Ability");
}
public native Effect foo(Effect x);
}
This code generates an *.h file without the foo() function, as if it couldn't recognize it. It does generate a proper file if I swap the return type to int and don't include the com_test_Effect.
I do have both of the modules defined in the Android.mk file (com_test_Effect and com_test_Ability).
How to include an another c++ file directly in the Xyz.java class from which the *.h is generated by javah ?
Edit: The question can also be asked like this: Is there a way to pass C++-type arguments or return a C++-type value from a function that is an interface between C++ and Java ? (The interfacing medium being JNI.) For example, you can do so with basic types like int which then gets converted to jint and so on.
What about returning an Object:
private native Object fooNative(Object x);
Then convert it so that it has the same signature:
public Effect foo(Effect x) {
return (Effect)fooNative(x);
}

GroovyClassLoader - adding parsed classes to classpath

I've got a library that allows clients to provide a list of text files, each of which contains groovy code for a class that extends java class Z. For instance file 'A.groovy' contains
package com.mypkg;
public class A extends Z {
#Override
public void someMethod() {
// do something A-ish
}
}
etc.
The library compiles each of these and (in this case) would return to the clients an instance of type Z.
My issue comes when a client needs something like this:
package com.mypkg;
public class B extends A { // extends A!
#Override
public void someMethod() {
// do something B-ish instead of A-ish
}
}
where B extends A, and class A was parsed before class B.
The issue is that the GroovyClassLoader can't seem to find class A, even though it just parsed A. Here's the code that compiles the scripts and creates the instances:
for (String fileName : listOfScriptFiles) {
InputStream in = getInputStreamFromFile(fileName);
CompilerConfiguration compConfig = new CompilerConfiguration();
GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread()
.getContextClassLoader(), compConfig);
Z service = null;
Class clazz = classLoader.parseClass(in);
service = (Z) clazz.newInstance();
return service;
}
Is there a way to 'register' class A with the runtime so that when Groovy tries to compile class B it will not complain that class A doesn't exist?
UPDATE
I was actually able to solve this by instantiating the GroovyClassLoader outside the loop that iterates through the client's code list, so the classloader that parses A is the same that parses B.
The question still stands, though, because I could envision a case where in one part of someone's code they parse A, and then in a completely different part, where the same classloader is unavailable, they parse B.
In my experience with the Groovy classloader (which is similar in behavior with Ant and beanshell's classloader in this respect) , you have to decide up front whether you are going to use the default system classloader, in which case you would build the classpath into the command that launches the Groovy script, OR on the other hand, you specify ONLY the groovy jar on the command line classpath and then you dynamically add classes at the beginning of your Groovy script on the custom classloader.
You aren't providing much information in your question, but my guess is that you put class "A" on the classpath before you launched the script and then your trying to load class "B" dynamically. That wouldn't work as far as I know.
NOTE: I myself have been trying to figure out how to do this kind of thing. It seems it would be possible but I still haven't figured it out.

Categories

Resources