I have the follow scenario to work on. I was given a shared library (libeffect.so) to use in a Android project i am working for a client. I dont have the shared library source code, i have just the .so file with me. The library is pre-compiled to work on android devices. Along with the shared library I have the method signature
public static native void doEffect(int param1, IntBuffer intBuffer);
So now I have some questiosn on how to make the call to this native method, of source, if this is possible having just the .so file, so there they are:
Do I need to place the native method signature in the same package/class as those defined when the .so was or I can use this signature in any package/class in my project that during runtime the jvm will be able to find the method in the shared library? For example, if this shared library was firstly used in a class mypackage.MyClass, do I need to create the same package, class and then put the method signature there?
Where do I need to place this .so file inside my eclipse android project to get this file deployed inside my apk file?
These question might sound noob, but I have never worked with jndi before so I am a bit concerned if calling the method doEffect without any error can be achieve. Any answer that can guide me is very welcome.
Many Thanks
Thiago
Do I need to place the native method signature in the same package/class as
those defined when the .so was or I
can use this signature in any
package/class in my project that
during runtime the jvm will be able to
find the method in the shared library?
For example, if this shared library
was firstly used in a class
mypackage.MyClass, do I need to create
the same package, class and then put
the method signature there?
No need to create same package/class. You can put the method signature in any package.
public class NativeLib {
static {
System.loadLibrary("so_file");
}
public static native void doEffect(int param1, IntBuffer intBuffer);
}
2.Where do I need to place this .so file inside my eclipse android project
to get this file deployed inside my apk file?
You have put this .so file in lib folder of your application . IF lib folder is not there then you can create a lib folder and put the .so file. you can call it by using System.loadLibrary("so_ file");
1 Do I need to place the native method signature in the same
package/class as those defined when the .so was or I can use this
signature in any package/class in my project that during runtime the
jvm will be able to find the method in the shared library?
According to http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html you have to use a matching package and class name.
I've only observed JNI methods where the C side functions are called things like Java_com_company_whatever_SomeClass_someMethod, which means that you have to put the 'native' declarations in a similarly-named Java class.
Use the tool 'nm' or 'nm++' (they're in the precompiled folders in the NDK) to look at the .so file and see what the functions defined in it are called. If you see any starting Java_, those're what you want.
I'm sceptical of the preceding claim that you can call functions which aren't named in the Java_PACKAGE_CLASS_METHOD format; it may be a legacy behaviour if it actually works, but even if you can, it seems dangerous - you might get the wrong one.
2 Where do I need to place this .so file inside my eclipse android
project to get this file deployed inside my apk file?
Your .so lives in libs/armeabi, libs/armeabi-v7a, libs/x86, and/or libs/mips depending on how many platforms you're working with, where 'libs' is a peer of 'src' and 'res'. I don't know whether Android looks in libs/ without the platform qualifier, but there's no evident benefit in that. The situation is slightly complicated by most/all Intel devices including fancy technology allowing them to execute most ARM libraries on x86 hardware.
Further, I like to declare an interface of a JNI class and provide a factory (it's a method here for brevity, but I prefer a factory class) that supplies a no-op implementation of the interface if things go wrong: it facilitates unit testing and also avoids having to mess about testing for null values before calling its methods (assuming you're comfortable that your shipped library will never have missing or changed method signatures - your integration tests should check that):
public interface YourLibI {
#Override
public native yourMethod();
public static final NO_OP = new YourLibI() {
#Override
public void yourMethod(){}
}
}
public class YourLib extends YourLibI {
public newYourLibI() {
try {
return new YourLib();
}
catch (UnsatisfiedLinkError e) {
Log.e("YourLibJNI", "Load failed, returning NO-OP dummy", e);
return YourLibI.NO_OP;
}
}
static {
System.loadLibrary("arbitronSDK");
}
private YourLib() {
}
#Override
public native void yourMethod();
}
I don't normally call interfaces 'xxxI' but I'm assuming your library's JNI class isn't called something nice like UtilityJNI (whereupon I'd call the interface 'Utility').
Related
I have a class name String and a String which containing the class code. For example, "Example" is the name of the class, and
public class Example {
public void example () {System.out.println ("Hello world!"); }
}
The class code.
I looked at the Dexmaker library, but I did not understand if it's possible to compile the generated code into it. And the question is just how to compile the code string under Android?
Not sure if possible at all the compilation within the embedded system but definitelly you can parse and run the code using beanshell:
http://www.beanshell.org/
it is lightweight and easily to embed in your app. Then you can instance the generated class and run whatever you put inside.
There is only one true way: using DexMaker. All examples you can find on DexMaker wiki and especially for current problem (runtime generation code on android).
I have a JNI library that I've written to capture sensor (mostly accelerometer and gyro) data and do some feature detection algorithms on said data. The features detected are configurable via a few configuration files. When the features are detected, the JNI uses a callback to notify the java side of the application. All this works great.
Now I want to be able to have multiple instances of the same JNI library running simultaneously (so I can recognize features from multiple configuration files at once). To do this, I wrote a 'wrapper' class that implements the callbacks for the JNI library and takes care of all the initialization of the library as well. I was planning on simply instantiating this class and using each instance separately. What I've found is that while each wrapper instance is distinct, the library is reused across instances almost like it was statically declared. When I try to initialize the library from the second instance of the Wrapper class, I find it has already been initialized.
Here is a wrapper class similar to the code I've written:
public class JNIWrapper {
public native int initializeJNI(String configPath);
public native void endProcessing();
public native int getInstanceIdFromJNI();
public JNIWrapper(){
try {
System.loadLibrary("libjnicode.so");
}
catch (Exception e) {
Log.e("JNI", "WARNING: Could not load libjnicode.so: " + e.getMessage());
}
}
public int initialize(String configPath){
return initializeJNI(configPath);
}
public void stop(){
endProcessing();
}
public void callbackFromJNI(int output, int instanceId){
//notify the subscribed application(s) of the feature detection
//via message passing.
}
}
Does anyone know how I can instantiate multiple copies of a JNI library?
Thanks!
You can't do that. The dynamic linker will only load a given .so file into a process once.
Ideally you would modify the library to give it a light object-oriented style, allowing you to create instances and initialize those (rather than process-level static state) from your configuration files or calls. This isn't necessarily as complicated as it seems - basically put all your state in a struct and pass the pointer to it through all your calls. You'll have one marathon editor session resulting in a tired "paste" finger, and then some mistake cleanup. Fortunately once you remove the static variables you'll get compile errors on all remaining attempts to use them.
A very hacky alternative might be to declare some remote-process services in your AndroidManifest.xml and load the library into each of those. Or, really breaking the android model (and at theoretical risk of random killing), load the library into multiple created-on-demand native executables.
I'm trying to modify chromium on android for research purposes.
Chromium comes with a ContentViewCore.java class. This class calls a native function:
nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
This method is defined in the same class as follows:
private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl,
String script, JavaScriptCallback callback, boolean startRenderer);
The class has the following annotation:
#JNINamespace("content")
As I understand it, the JNI Generator links these methods to the correct native (c++) methods of the correct class.
My question: To which class is ContentViewCore.java linked? Where can I find the implementation of nativeEvaluateJavaScript? Where is it defined that a specific java class is linked to a specific c++ class?
The only thing I can find is content_view_core.h (src/content/public/browser/android), but that file doesn't get me any further. Googeling for 'nativeEvaluateJavaScript' revealed nothing. I've been searching for about 10 hours now and I'm not getting any closer.
The JNI generator will generate JNI binding file under "(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)/jni/" during the build time.
For example, the corresponding JNI binding file for ContentViewCore.java is "out/Debug/gen/content/jni/ContentViewCore_jni.h". And you can see the native method of 'nativeEvaluateJavaScript':
static void EvaluateJavaScript(JNIEnv* env, jobject jcaller,...
I have a android application, say 'OldApp', which uses some native methods within itself, and I have to use it as a library for a new app, say 'NewApp'.
This is the first time i work with this request and i have a doubt:
the OldApp has some classes, and one of these is the JNI Wrapper and contains the native methods, for example:
public class LibOldApp {
private static native int method1();
....
....
}
Can i use all the classes/methods of the OldApp or only the wrapper, and native methods?
thank you..
Yes sure you can use.
just use your old app as library for your new project.
Suppose I have my Android app's source code packaged this way:
src/
my/
app/
Module.java
ModuleManager.java
module/
ModuleA.java
ModuleB.java
where Module is:
public abstract class Module {
public abstract void run();
}
, ModuleA and ModuleB extends Module:
public class ModuleA extends Module {
#Override
public void run() { /* do something */ }
}
and ModuleManager has some helper methods, among which one to retrieve all the Modules:
public class ModuleManager {
private final static List<Module> modules;
static {
List<Module> tmp= new ArrayList<Module>();
tmp.add(new ModuleA());
tmp.add(new ModuleB());
modules= Collections.unmodifiableList(tmp);
}
public static List<Module> getModules(){
return modules;
}
}
As you can see I manually filled the list of modules in ModuleManager. Instead, I would like it to be automatically filled with an instance of all the Module's subtypes in the module package.
I tried in several ways reflection-based solutions like this, which involve the use of ClassLoader::getResource(String path) to retrieve every .class file inside the module package, but it always returns an empty enumeration. I learnt this is due to the difference between Dalvik's VM and Java SE's one, and its optimized packaging of .class files inside classes.dex. I then tried to import the application's apk from /data/app/ with DexClassLoader or PathClassLoader and unsuccesfully tried their getResource() method again. Anyway I think this is not the right direction, and probably this stuff was already hackish/flawed in Java, and it would be even more in Android.
Could you suggest me a way to do that?
Thank you very much.
One way to do this in a build script, after compilation but before dex is called to create classes.dex, run a small script to get the class names in modules folder and write it to say an application.properties file to read from (or strings.xml in resources).
The disadvantage of this is it is not a pure java method you were asking for, the advantage being it will work for 2 or 10+ subclasses. Hope this helps.
What if you add an XML or a Properties with the module classes and you dynamicly created from it... it might goes something like this
<modules>
<module>
my.app.module.ModuleA
</module>
<module>
my.app.module.ModuleB
</module>
</modules>
Another solution could be to exploit a naming convention on classes' names and retrieve all of them one-by-one with Class.forName(className). In the example I made, if I know that all modules are named sequentially as ModuleA, ModuleB, ModuleC and so on, I can retrieve all of them starting from ModuleA and continuing until Class.forName("ModuleX") fails. If gaps were allowed but the number of modules was bounded (and very low), an exhaustive search on the entire range could be done.
Of course this could be applied in a very few cases, and at the expense of class' name readability.