Fixed
Status Update
Comments
il...@gmail.com <il...@gmail.com> #2
In the meanwhile, I've taken out the relevant code from lo-bootstrap.c and repackaged it into an NDK import module for everyone's pleasure:
https://github.com/ikonst/android-dl
[Deleted User] <[Deleted User]> #3
Excellent work Ilya! I'm still hoping this gets fixed in Android proper (for code portability reasons) but at least now we have a workaround.
en...@google.com <en...@google.com>
en...@google.com <en...@google.com> #4
"You should not call dlopen() unless you are sure it will succeed" --- that's a separate bug: http://code.google.com/p/android/issues/detail?id=22143
[Deleted User] <[Deleted User]> #6
I must tell you, I've been looking forward to this feature for a long time now :) It improves portability for headless libraries that run both under Java and Android platforms (such as JNA).
Under the new API do just call System.loadLibrary() and it'll do the "right thing" under the hood? Or do we need to do anything extra to get this to work?
Under the new API do just call System.loadLibrary() and it'll do the "right thing" under the hood? Or do we need to do anything extra to get this to work?
il...@gmail.com <il...@gmail.com> #7
Just done skimming over the code. Good work guys :)
Yes, it updates LD_LIBRARY_PATH upon app startup, so both System.loadLibrary and dlopen works as you'd expect. See the big comment inhttps://android-review.googlesource.com/#/c/48407/1/luni/src/main/java/java/lang/Runtime.java
Yes, it updates LD_LIBRARY_PATH upon app startup, so both System.loadLibrary and dlopen works as you'd expect. See the big comment in
il...@gmail.com <il...@gmail.com> #8
Created issue 36949180 to track NDK docs change.
il...@gmail.com <il...@gmail.com> #9
Elliott, just wondering:
I've seen you're passing the LD_LIBRARY_PATH through BaseDexClassLoader.
Except for the sole purpose of passing the LD_LIBRARY_PATH around, does BaseDexClassLoader even need to know the library path anymore, now that dlopen will be doing the right thing?
I've seen you're passing the LD_LIBRARY_PATH through BaseDexClassLoader.
Except for the sole purpose of passing the LD_LIBRARY_PATH around, does BaseDexClassLoader even need to know the library path anymore, now that dlopen will be doing the right thing?
en...@google.com <en...@google.com> #10
the problem is that ClassLoader actually has a hand in how dynamic libraries are loaded. this is a stupid mistake, but it was made in 1995, so we're probably stuck with it.
if i had a time machine, i'd remove all the findLibrary crap from ClassLoader, i'd remove the native library paths from all the various ClassLoaders, and i'd make the Android frameworks update the dynamic linker, and i'd pass whatever System.loadLibrary sees straight to dlopen(3).
since i'm not in the dogfood program for Sergey's time machine project, i think i'm stuck trying to support these paths.
we did consider just ignoring the ClassLoader paths, but worried about the possibility of someone installing their own ClassLoader with a (deliberately) different native library path. we won't be breaking that case either way, but if we want to _fix_ it, we need to honor the path set in the appropriate ClassLoader for the loadLibrary call. (the main problem with this is that it's actually a lot easier to create a new ClassLoader with no native path than one with the correct native path. but in every scenario i can think of, anyone doing that kind of thing is no worse off.)
we've discussed the choices a lot internally (and on the patch review comments) and i don't think any of us is really happy, but i think we're at a consensus that the currently-uploaded patches are our least worst choice. i'll prod the reviewers and try to get the patches merged today...
if i had a time machine, i'd remove all the findLibrary crap from ClassLoader, i'd remove the native library paths from all the various ClassLoaders, and i'd make the Android frameworks update the dynamic linker, and i'd pass whatever System.loadLibrary sees straight to dlopen(3).
since i'm not in the dogfood program for Sergey's time machine project, i think i'm stuck trying to support these paths.
we did consider just ignoring the ClassLoader paths, but worried about the possibility of someone installing their own ClassLoader with a (deliberately) different native library path. we won't be breaking that case either way, but if we want to _fix_ it, we need to honor the path set in the appropriate ClassLoader for the loadLibrary call. (the main problem with this is that it's actually a lot easier to create a new ClassLoader with no native path than one with the correct native path. but in every scenario i can think of, anyone doing that kind of thing is no worse off.)
we've discussed the choices a lot internally (and on the patch review comments) and i don't think any of us is really happy, but i think we're at a consensus that the currently-uploaded patches are our least worst choice. i'll prod the reviewers and try to get the patches merged today...
en...@google.com <en...@google.com> #11
this is in jb-mr2.
ok...@gmail.com <ok...@gmail.com> #12
Sorry to comment on an ancient issue, but I'd just like to add that jb-mr2 means that this works on API level 18 and up.
sa...@gmail.com <sa...@gmail.com> #13
> b-mr2 means that this works on API level 18 and up.
Sorry to disappoint you, but experimental evidence shows that we need to load local dependencies manually even for KitKat.
Sorry to disappoint you, but experimental evidence shows that we need to load local dependencies manually even for KitKat.
ok...@gmail.com <ok...@gmail.com> #14
I just tried it with like 6 different API levels before commenting and it was not working on 17 and definitely working on 18 and later
sa...@gmail.com <sa...@gmail.com> #15
Sorry, my bad. Found a device with JELLY_BEAN_MR2, verified that it works, fixed my workaround.
Description
Instead of leaking platform-specific behavior into application code, we could load the transitive dependencies automatically.
lo_dlopen(), found at
- Searches where the shared object in question is. It searches a set of directories passed to it by the Java code. The Java code looks at LD_LIBRARY_PATH and adds the app's lib directory to that.
- Opens the found shared object file and reads the ELF structures in it . Not all, but just enough to find out what shared objects it needs (the DT_NEEDED ones as displayed by arm-linux-androideabi-readelf -d). It calls itself recursively on the needed shared objects.
- Only after that, i.e. after making sure that all needed other shared objects have been loaded, it calls the real dlopen() on the found full pathname to the shared object.
A few gotchas that the code handles:
- You should not call dlopen() unless you are sure it will succeed. The Bionic dynamic linker "helpfully" remembers if a dlopen() call has failed and refuses to even try again dlopening the same library a second time, even if you after the first attempt have loaded the required dependencies that caused the failure the first time. I.e. it is not a good idea to just try dlopen() first and if it fails, parse the dlerror() message...
- The wrapper needs to remember what libraries it already has loaded to avoid infinitely looping when libraries have circular dependencies (which they do have).
Benefit: Improved portability for application or library code (versus having to add Android-specific workarounds for System.loadLibrary()).