Calling System.loadLibrary twice for the same shared library - java

I have the situation when two jar libraries use the same shared library.
In each library "the main interface" class loads the .so file with System.loadLibrary.
My question is: if the user decides to use these two jar libraries in one project, would the second call to System.loadLibrary for the same .so file cause any exception? Or is it "somehowe handled" by the system to prevent shared libraries from being loaded twice? Or maybe there is a "commonly known pattern" to handle such situations?
The jni wrappers are targeted to be used on android. I am the author of both wrapper libs so answering you can assume full control on java sources.

According to the apidocs it should not be a problem: "If this method is called more than once with the same library name, the second and subsequent calls are ignored."

I've found one very narrow use case when this will be a problem.
If you are running Android system app, with android:sharedUserId="android.uid.system" in manifest, either pre-installed to the device, or signed with the platform certificate, and you are trying to call System.loadLibrary twice to load the same library (either by running the same app twice, or creating two separate system apps loading the same library), Android will reboot.
Invoking JNI method from this library, if it was not yet loaded, will not generate an exception when running inside android.uid.system process, as with normal Android app - it will reboot Android.
To prevent that, and find out if the library was already loaded, you can read file /proc/self/maps and search for your library name there. ClassLoader and reflection will not help here - they will show JNI methods as accessible even when the library is not yet loaded.
Note that you cannot do if (Runtime.getRuntime().exec("/system/bin/grep <library-name> /proc/self/maps").waitFor() == 0) - system process is forbidden from launching any external commands by SELinux, you will have to read the file from the Java code.
Another quirk is that the library must be preinstalled to device to the /system/lib directory - if you bundle the library with your app, and install the app to device, library will end up in /data/app/..../lib, and when you will try lo load it from /data partition, well you already guessed - Android will reboot.

Related

Android java app installation under the hood

I am trying to understand what exactly is going on when you install an application (APK) on an Android device. I guess that files are are extracted from the package and copied somewhere on the device.
Are there other steps going on? For example, is the package name of the application written somewhere in the OS like in somekind of registry?
Is the application version number written as well somewhere or the OS reads the xml manifest of the application to know its installed version?
This is related to another question where I suspect that some data was not erased correctly during the uninstallation of a debug app and I am trying to find what that might be.
There will be files/dirs created in various locations, not necessary in all possible locations for every app though, it depends on how the app is configured.
This list is not necessarily complete.
Files/dirs:
/data/data
/data/app
/data/app-asec
/data/app-lib
/data/dalvik-cache
/data/local/tmp
/mnt/asec
/mnt/obb
/mnt/sdcard/Android/obb
/mnt/sdcard/Android/data
Your app will also get an entry in these files:
/data/system/packages.list
/data/system/packages.xml
/data/system/appops.xml

Some customers get a java.lang.UnsatisfiedLinkError when upgrading my Android app. How do I fix this?

Several random customers get this exception every time I update my Android app. I've narrowed it down to two reasons, both related to using the jni.
The *.so library is deleted when the app is upgraded.
The *.so library is not upgraded when the app is upgraded, and the old version still remains.
The device reports do not signal that this issue is related to the OS version, memory, or anything rational. Rather than focus on why Android is having trouble upgrading the libraries, I'm hoping someone out there knows how to manually pull the libraries out of the app's APK and put them in the right directory when this error is encountered.
Seems like you probably have an ABI mismatch - or possibly a false ABI mismatch caused by an Android bug that people have been talking about, where a generic arm library may not be accepted when one of the specialized varieties is preferred.
As for your workaround... you cannot write to the lib/ directory of your app's installation, though you can put a library elsewhere if you use System.load() with a precise path/filename instead of loadLibrary() with just a library name. I don't think there's any official (as in future-proof) way to extract arbitrary contents from your apk, though it's fairly easy to do at present with the zipfile classes (with something perhaps such as Context.getPackageCodePath() to discover the location and installation-variable name of the apk)
Checking for the success of the library loading attempt and reporting information about the device if it fails might be as useful.

How does the android build system handle java libraries which load native shared libraries

Consider the following situation: I have two android projects named P1 and P2 which both produce an apk which use the same process-id and will run in the same process on android.
P1 and P2 both use Java library JL1. JL1 loads at runtime shared library1 SL1.
What I see runtime is that at some point I get a java/lang/UnsatisfiedLinkError while loading this SL1.
It also outputs: Shared lib already opened.
What causes this problem? I'm assuming that library code in java is sort of copied in every project/apk and at runtime when apks are merged in one process it forgets about the copies. So every copy loads its shared library itself, causing the already loaded error.
If so, isn't this unwanted behaviour. Because, now you can never have a java library with an shared library in the same process used more than once.
[edit] I found out that every apk uses its own class loader (also when in the same process). This means that every JL will be class loaded per apk and therefore every shared object will be loaded more than once, resulting in an error. Somebody any ideas how to get around this? Is it possible to let apks share a classloader?
Every apk has its own class loader. This means that two projects/apks will have there own copy of classes from the library. Which they load at runtime. Therefore what looks like the same classes are actually copies. Therefore loading a native library in such a class will result in loading it for every loaded class (even if this is done in the static field). Which results in a runtime error for loading the native shared object more than once if the two apks share the same process.

Stop Selenium 2.0 Webdriver from creating temp files IE

Whenever I run my script a temp file gets created in my local directory:
something like: "webdriver4726826335276373500libs"
inside the folder: IEDriver.dll
at first I thought it was this issue
How to stop Selenium from creating temporary Firefox Profiles using Web Driver?
but that does not seem to be the case, I do not think that IEdriver uses profiles.
This is a problem for me because it is eating up my hd space.
does anyone know why this is happening?
The core of the IE driver is contained in a COM dll written in C++. For certain language bindings (.NET and Java), this dll is extracted at runtime to a temp folder when you instantiate an instance of the InternetExplorerDriver class. These languages then use their native code invocation mechanism (JNA or P/Invoke) to call the functions in the native code dll. This methodology was chosen to reduce the requirement on the user to have the correct .dll (and the correct version of the .dll) in a known location. At present, it doesn't appear that the Java language bindings do anything to delete this .dll after the server is shut down, whereas the .NET bindings do. The report tracking this issue for the Java bindings in the project's issue list is issue #1140. As a workaround, you can manually delete these directories after running your tests, or it may be possible to create a short routine in your testing framework that will do the same.
The driver.quite() will automatically clears your temporary files. you better look at this.

Automatically update jar files

I am currently working on desktop software based on java.It's quite a big code base (more than 40 jar files).
I wish to provide an automatic update functionality. The desktop software constantly checks one back end system to see if there are new versions of the jar files available.
The problem now is: How to replace the updated jar files?
If you deploy your application using Java Webstart (JNLP), you get this mechanism almost for free...
From http://mindprod.com/jgloss/javawebstart.html
The key benefit for Java Web Start is automatic update without having to download the entire program every time.
Easiest would be to check for updates on each startup, download the updates and then launch your application. I think this is the way that Java Web Start works (see aioobes answer).
More complex would be to use either the netbeans or eclipse framework for your application. Both are rather complex and you will have to rewrite your application to work with them. This solution supports live updates.
As far as I am aware there is no easy way to update a running application. It is possible to load new versions of a class with a different classloader, but not possible to unload old versions while they are still referenced.
You can make a little server and a launcher which downloads the newest version, replaces the old one, and starts the jar with:
Runtime.getRuntime().exec("java yourjar -jar");
And you terminate the launcher with:
System.exit(1)
You can also serialize down your state (keep it in memory) and then create a new ClassLoader instance pointing to the new .jar files. Then serialize up your state again using this new classloader. You have just changed the underlaying .jars within a executing product.
Please note that you do not need to change the classloader for everything only for the part that is actually using the .jar files. This can be tricky to conclude what parts that are. And you might get nasty linking errors if done wrongly. So..
.. to keep it simple, use WebStart or a preloader that updates the .jars and then starts the main app (basically what WebStart does for you).
A reason for rolling your own, is that you can use your own format for the .jars, encryption, other packing formats etc.
After reading some answers to many auto-update questions, I thought of a solution. This is how I would implement a secure auto-update for a Java/Kotlin jar application.
Assumption: the installer will contain two jars: a launcher and the main application. Any shortcuts created will point to the launcher, but still be the name of the application. The release will contain the main application and the installer.
The launcher is launched first:
First check if an update has already been downloaded as app_name_update.jar
if an update has been downloaded, rename app_name_update.jar to app_name.jar
Start app_name.jar
This part does not have to be in the launcher, but it's preferred as to not slow down the main application: at this point, the launcher should check for an update (e.g. GitHub releases API) and download it to {CWD}/unverified_app_name_update.jar.
Compare the hash of unverified_app_name_update.jar to an online location containing hashes for all published versions. hashes.txt would be an example found in the same github repository. If the software is open-source, GPG signed commits is a must and the launcher should check if the latest update is a verified commit! If its a proprietary application, keep the hashes.txt at a separate URL from the release where your company does not control the infrastructure (e.g. GitHub).
Main app launched:
No need to check for updates unless updates are mandatory, in which case check for update -> if update found, start loading animation "updating" while you can detect that the launcher is still running. Ensure that the launcher has no race condition while loops!
I found ready project to solve automatically updating.
You can update your app, in your cases you can update jars and resources of your desktop app. The idea of the this is next: wrap you app with starter which can control updating and running you app. In details you can find here.

Categories