1

No comments about security concerns please, this is a very specific use case.

I am building an Android app that has two native libraries. We'll call them libFooA.so and libFooB.so. Now, libFooA.so is bundled inside the APK. However, it depends on libFooB.so, which is NOT bundled inside the APK. Instead, it is dynamically loaded from the internal storage at runtime using System.load().

Now, because libFooA.so depends on libFooB.so, I have to load libFooB.so first, (using System.load()) before I can load libFooA.so with System.loadLibrary(). Otherwise, I get this error:

dlopen failed: cannot locate symbol "SOMESYMBOL" referenced by "libFooA.so"...

Anyway so, this works perfectly on every single device running Android 6.0/7.0/8.0 that I have tested. However, it fails on every single KitKat device that I have tested. This led me to suspect that the issue was with Dalvik vs. ART. So I switched a KitKat device to ART through Developer Options and tried again, but it still fails. The perplexing thing is, the error that is thrown is exactly the same error that is thrown if I try to load libFooA.so before libFooB.so on a 6.0/7.0/8.0 device.

Additionally, the problem does not lie with System.load() itself on KitKat, as I have been able to successfully dynamically load and use native libs on KitKat before. The issue here is when trying to System.loadLibrary() a lib that depends on another lib which was loaded with System.load().

I have not yet been able to test on a Lollipop-based device, but I suspect it would work fine. Anyone know why KitKat is having an issue here? Is this a known bug with KitKat?

UPDATE: Fails on 4.4/5.0 ARM Android emulator. Works on 6.0 ARM Android emulator.

UPDATE 2: I think the answer lies on this page, could someone point me to which exact item causes the behavior change that lets this work on >= API 23?

JoshDM
  • 4,939
  • 7
  • 43
  • 72
  • I MAY BE WRONG, but I have read that if you just System.loadLibrary(FooA.so) it should find the dependency of LibFooB.so as long as libFooB.so is in the java.library.path, with no need to load it explicitly. loadLibrary() does a dependency search; .load() does not do this. This site https://www.pixelstech.net/article/1549365534-The-difference-between-System-load-and-System-loadLibrary-in-Java is where I read about it, but haven't tested it. – JoshDM Aug 26 '19 at 22:10
  • Relevant text from that site: Another difference is related to dependency between native libraries. Assume two native libraries A.dll and B.dll. A.dll is statically linked to B.dll. If using System.load("D:/A.dll"), it would throw exception even if B.dll is under the same directory as A.dll. JVM finds A.ddl depends on B.dll when trying to load A.dll; it will try to find B.dll under java.library.path but B.dll is not found. 2 solutions: (1) Call System.load("D:/B.dll"), then call System.load("D:/A.dll") or (2) Put A.dll and B.dll under java.library.path and then call System.loadLibrary("A") – JoshDM Aug 26 '19 at 22:16
  • @JoshDM I think that's unrelated. I think the *"Correct soname/path handling"* section of the site in my second update contains the answer – You'reAGitForNotUsingGit Aug 26 '19 at 22:37
  • @JoshDM besides, it works on >= Android 6.0 – You'reAGitForNotUsingGit Aug 26 '19 at 22:39

0 Answers0