Use prebuilt JNI library in Android Studio 3.1 - java

I was given a shared object (*.so file) that I need to reference from my app. I know for a fact that the shared object uses JNI. Now, I have some experience with Android app development, but none with native code. I have looked at a lot of answers here on StackOverflow and on Google in general, but none seem to fit in my question.
Basically, this shared object was for another app, and I have the code for that app, and now I need to implement it in my app. I am lost as to where I should start or what I should do. If anyone can help guide me through this process that would be very nice.
Also, I do not have the source files nor the header files for the shared object. I do know the name of the native method.

If you don't have the Java sources that defined these native methods originally, you can often reverse engineer the necessary native method definitions from the .so file itself. E.g., if the library exports Java_com_example_testjni_MainActivity_stringFromJni, then you must add a Java class
package com.example.thestjni;
class MainActivity {
public native static String stringFromJni();
}
This does not give your the correct parameters or return types for the native methods. Also, you must guess whether the native method should be declared static or not.
To be on the safe side, you will add a static constructor to this class, to make sure the library is loaded:
package com.example.thestjni;
class MainActivity {
static {
System.loadLibrary("thirdparty");
}
public native static String stringFromJni();
}
You are free to rename the 3rd party library to your liking, but not the package and not the class. You don't care if the original Java class declared the native method private, you can safely declare it public in your project.
To find the names of JNI functions exported by prebuilt library libthirdparty.so, you can use the nm tool provided with Android NDK toolchains:
nm -D libthirdparty.so | grep Java_

If you have the Java code for another app that uses it- find the Java code in the other library that calls it. Those functions should be defined with the keyword native. Take that class(es), without renaming or changing the package, and put it in your project. Now you can call those native functions via the Java native function definitions.
Of course without source you can't compile for any other architecture. So hopefully you have the .so files for all the appropriate ones. Remember to load the library if those class(es) don't do it for you.

Related

Is it possible to override files from android sdk?

For example i want customize BluetoothGatt class. Is it possible to create android.bluetooth package and put own version of this class?
BluetoothGatt uses android interface files shown in here. Can i access these files and use it in own version of BluetoothGatt?
Yes as long as you match the package and class name, when you reference it in your code, you will be able invoke your custom behaviour / modified contract
Android classes are simply Java. You can modify the support SDK, as it is simply a Java file. However, this is only applying to your app, or it would be possible for apps to change the entire SDK, which is defeating the point of sandboxing. If you want to extend the class, that is done just the same as in Java, as the class is just Java. However, this specific class is final, so you can't, at least not without hacks. However, the support library is usually a wrapper, so you may as well write your own. If the reason you want to do this is to access a private method, use reflection!
EDIT: To pedantically answer your question, you have already accessed said files, and copy-and-paste is always your friend!
Hope I helped!

JNI_OnLoad get Java caller package+class name

Is there a way to get Java package and classname from which native library was initialized from JNI_OnLoad? I want to reuse my native library in multiple Java projects and don't know in advance classname and package from where LoadLibrary("mynativelibrary") is called. Then I could use JNI RegisterNatives with dynamic classname.
I've come across the same problem recently. I ended up reusing the class (i.e. copying the code) which loads the native library and handles all callbacks into other projects keeping the original package name. If you make that class generic and use an interface for callbacks then it shouldn't have any dependency on the project and so can be used anywhere. Works well for me.

Accessing a third party DLL using JNA

I am trying to access a 3rd party c++ DLL using JNA. I have looked at the JNA documentation available and some blog for understanding JNA.
But now I am stuck with a problem. The DLL which I have has multiple classes in it. And the functions are defined inside the classes. So there is a hierarchy. How can I access the functions then?
For example I have a DLL named: "abc.dll'. In this dll I have class "pqrs" and in that class there is a function called xyz(). I want to access xyz() function.
Until now I am able to load abc.dll successfully as following:
abc abcDLL = (abc) Native.loadLibrary("abc", abc.class);
I have created a interface like this:
public interface abc extends Library {
void xyz(); // this is wrong because "xyz" is not directly "abc.dll" but inside the class "pqrs" which is inside abc.dll
}
And like this there are multiple classes inside the dll. I have searched the web a lot about this. But could not find a solution. I came across to these posts:
Accessing DLL methods with contain mulitple classes using JNA
http://www.javaprogrammingforums.com/java-theory-questions/8865-using-jna-access-export-native-classes.html
But nobody has answered there.

No java imports in smali?

I was doing some experiments today in android source.
Let me tell the complete thing,
I compiled framework.jar from android source and decompiled it and generated smali source and kept it aside. Then from CyanogenMod repo I added the commits of a feature to android source and compiled framework.jar again and again decompiled smali source to see the changes in terms of smali so that I can port them over to my ROM.
The feature I am porting requires importing of certain classes e.g import dalvik.system.VMRuntime and extra coding for utilization of those imported classes. So now my problem is, I am only able to see the extra coding i.e utilization of those classes in the smali code but not those imports. So when I port only the smali code I get java.lang.NoSuchMethodError in logcat which shows that it is unable to find that method. The reason is clear because the necessary class is not imported then how to do it in smali code? i see no way to do that in smali and due to which the newly introduced methods don't work.
Any feasible solution to this?
The only thing an import does in java is make it so that you can mention a class without having to specify the full package name. In smali, there are no imports - everything always uses the fully qualified class name that includes the package.
As such, your problem is definitely not related to imports. It sounds like you are trying to use a method that simply doesn't exist on the device.
You can disassemble the framework jars from your device and find the definition of the dalvik.system.VMRuntime and see what methods are available. Or alternately add some reflection calls and log the info to logcat.
It's worth noting that VMRuntime is not part of the public API, and it may not be present or consistent on all devices or future versions of Android.
(I don't know smali, so there may be a much better solution)
No Java program ever requires any import statement. To use e.g. ArrayList you need to either import it or refer to it in full, as java.util.ArrayList.
There is a significant difference between e.g. a C++ #include and a Java import. A C++ #include directly inserts code in your program, typically the declaration for a class you are using. The process of getting the declarations is divided into two stages in Java. First the compiler determines the fully qualified class name, then it uses its own library and the classpath to find the declaration for that name. Java import is used only in calculating the fully qualified class name, and so is not needed for any class that is only referred to by its fully qualified name.
Perhaps you could pre-process the code you are adding to replace e.g. VMRuntime with dalvik.system.VMRuntime etc. so that you can compile it with no imports.
Here is an example of a short program that uses java.util classes, in different ways, without any import:
public class Test {
public static void main(String[] args) {
java.util.List<String> list = new java.util.ArrayList<String>();
list.add("bbb");
list.add("aaa");
java.util.Collections.sort(list);
System.out.println(list);
}
}

Call JNI methods that were not written for your class

It seems that JNI methods need to be written with the Java class signature built in to them. I want to call a JNI method that I didn't write. Can I call a native method on a library that was not written with my class in mind?
Given:
package com.mycompany.package
class MyClass
{
public native void doSomething();
}
is transformed (mangled) into a natively linked method name of:
Java_com_mycompany_package_MyClass_doSomething
it seems you would need the same class in the same package in order to connect the native method to the Java method. This seems like it's likely to be problematic and/or error prone if you don't have control over the native library. And packaging your code in a foreign package is a bad idea, esp. if the foreign package is signed and sealed.
Also problematic is that native invocation generally have some specific considerations which you might be violating - like thread-safety concerns, or releasing memory or lock (the need to call other native functions around the one you're using).
From my (considerable) experience with JNI I wouldn't recommend it unless you're desperate and have no other options, and you're really familiar with the target system and API.
Your better option would be to write a simple native wrapper around the target O/S API(s) you want to use.

Categories

Resources