You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[question] __emutls_get_address change in r23b causes compatibility issues for libc++_shared.so #1639
The fix in #1551 causes compatibility issues for libraries which are built using r23b. I couldn't find a solution for those problems. So, I'm posting my findings here. I'm still not sure whether it is an application error, an NDK issue or an Android platform problem.
When I build ffmpeg-kit with r23b everything works fine. I don't have any issues about building or running the .so files in any architecture.
However, some packages of ffmpeg-kit (there are 8 different .aar packages) are bundled with libc++_shared.so. If I depend on a second library which also comes with their own version of libc++_shared.so. And if that second libc++_shared.so is not coming from r23b then we have a problem.
Normally, I'm using the following configuration in build.gradle to pick only one of the .so files.
This conf drops my libc++_shared.so file, puts the one not coming from r23b and my application fails to start with an undefined symbol error.
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__emutls_get_address" referenced by "/data/app/~~2kB8d3EtNmrQeTorQuxsNw==/com.arthenica.ffmpegkit.reactnative.test-H8VCzoSNcb5BSErN7bf4mw==/base.apk!/lib/x86_64/libffmpegkit.so
In my case, the second library is React Native. React Native is shipped with an old version of libc++_shared.so.
Btw, this is how __emutls_get_address is defined in my libffmpegkit.so library. __emutls_get_address is undefined there.
readelf -s libffmpegkit.so | grep __emutls_get_address
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __emutls_get_address
The flags that I use to build ffmpeg-kit didn't change recently. The only thing in my toolchain that changed is ndk version. So, the question is:
Is there a flag or option I can use to build ffmpeg-kit to prevent this from happening?
If it did happen, is there a workaround I can apply, e.g. tell gradle to pick my libc++_shared.so not the one coming from react-native
Is this an app error or an issue that must be addressed in NDK?
Hmm. My gut reaction is that this is a packaging bug, but of course it's one that's very easy to encounter. I don't know enough about AGP's packaging DSL to tell you how to spell out the fix though. I would guess that there's some option other than pickFirst that will let you resolve a specific artifact instead.
I don't suppose React Native is available as an AAR? An AAR wouldn't have this problem because prefab packages don't include the stdlib for exactly this kind of reason.
Is there a flag or option I can use to build ffmpeg-kit to prevent this from happening?
I don't think so, and you'd be re-introducing a different bug by doing so (an admittedly rare one that you may not care about).
Is this an app error or an issue that must be addressed in NDK?
I'm not sure what we could do in the NDK here. Had this been discovered before r23b shipped, we probably would have avoided including the fix in that release. While it's not unlikely for things to break when you build against newer artifacts than are actually shipped, it's really not something we'd like to have happen within a major release :( A revert of the fix in r23c wouldn't help either, it'd just make the problem happen in the other direction (artifacts built with r23b wouldn't work with the r23c libc++).
I don't suppose React Native is available as an AAR? An AAR wouldn't have this problem because prefab packages don't include the stdlib for exactly this kind of reason
Actually, it comes with an .aar. But it doesn't have a prefab package inside. Btw, how can a prefab package solve this issue? I thought, a prefab package is simply C/C++ headers for the native libraries under the jni folder and the metadata that shows which headers belong to which .so. I guess it does more than that. Well, I can ask ReactNative to add a prefab package if that will help.
Prefab packages don't bundle the stdlib; they get it from your NDK. If you need a specific version of the NDK for your app, you pick it in AGP and it gets used no matter what your dependencies used (aside from some ABI compatibility checking).
Prefab packages don't bundle the stdlib; they get it from your NDK. If you need a specific version of the NDK for your app, you pick it in AGP and it gets used no matter what your dependencies used (aside from some ABI compatibility checking).
Does this mean that I will not have the cannot locate symbol "__emutls_get_address" error if I follow the following steps?
Build a prefab package with r23b for ffmpeg-kit and put in ffmpeg-kit.aar
Create an app where I have ffmpeg-kit.aar (with prefab) and react-native.aar (without prefab) as dependencies
Well, I don't remember I've seen the pickFrom option before. Had a look at AGP 4.1, AGP 4.2 and AGP 7.0 docs but I don't see it there too. I guess it was a suggestion to address the issue. I'll be happy to use it they decide to implement it.
Build a prefab package with r23b for ffmpeg-kit and put in ffmpeg-kit.aar
It shouldn't matter what NDK is used to build your dependencies as long as its output is ABI compatible (which means everything since r11 is valid, not that I'd recommend using anything that old 😄). If all your dependencies are prefab AARs they don't bundle libc++ and your libc++ will be used regardless of what they built with.
and react-native.aar (without prefab) as dependencies
If that's the package that's giving you the out of date copy of libc++ (seems so), if this is still a non-prefab import, this won't fix anything. I should probably mention that I have no clue how react native works so maybe this suggestion is completely off base.
From what I can tell the problem here is that react native is forcing an older (incompatibly older) libc++ into your APK. libffmpegkit is built correctly, it just requires a newer libc++. I don't think any changes to libffmpegkit will help you. I think the fixes available to you (aside from react native rebuilding with r23c) are:
libc++ stops exporting this symbol
AGP uses libc++ from your NDK and not from your dependencies
1 isn't really a solution. It might make the problem asymptomatic in some cases, but there's nothing unique about libc++ here that's causing the problem. If you had any other r23c+ built dependency that used thread locals, the problem would still be present. Hiding it in everything would solve that, but that was the cause of #1551. If TLS variables in a shared library need to be usable outside that library, __emutls_get_address must not be hidden in either library because otherwise there are multiple definitions of the function, and therefore multiple addresses for the thread local variable.
2 seems ideal, but I came to the same conclusion you did: there's currently no way to describe this requirement to AGP. I'm going to ask around and see if I can get a better answer on that. The advice we (both AGP and NDK teams) have been giving is that file conflicts like these cannot be automatically resolved and the developer must make the decision of which file gets packaged, so I'm pretty surprised to find that it's not possible to actually do that.
I'm pretty frustrated by this bug too, fwiw. There don't seem to many good options for a fix local to apps or the NDK. We'll keep thinking about it.
Activity
DanAlbert commentedon Jan 4, 2022
Hmm. My gut reaction is that this is a packaging bug, but of course it's one that's very easy to encounter. I don't know enough about AGP's packaging DSL to tell you how to spell out the fix though. I would guess that there's some option other than
pickFirstthat will let you resolve a specific artifact instead.I don't suppose React Native is available as an AAR? An AAR wouldn't have this problem because prefab packages don't include the stdlib for exactly this kind of reason.
I don't think so, and you'd be re-introducing a different bug by doing so (an admittedly rare one that you may not care about).
I'm not sure what we could do in the NDK here. Had this been discovered before r23b shipped, we probably would have avoided including the fix in that release. While it's not unlikely for things to break when you build against newer artifacts than are actually shipped, it's really not something we'd like to have happen within a major release :( A revert of the fix in r23c wouldn't help either, it'd just make the problem happen in the other direction (artifacts built with r23b wouldn't work with the r23c libc++).
CC @rprichard @smeenai in case they have better ideas.
Leaving open for now but I suspect my reasoning is right and anything we do to "fix" this actually just adds a second incompatibility.
tanersener commentedon Jan 5, 2022
Actually, it comes with an
.aar. But it doesn't have a prefab package inside. Btw, how can a prefab package solve this issue? I thought, aprefabpackage is simply C/C++ headers for the native libraries under thejnifolder and the metadata that shows which headers belong to which.so. I guess it does more than that. Well, I can askReactNativeto add aprefabpackage if that will help.DanAlbert commentedon Jan 5, 2022
Prefab packages don't bundle the stdlib; they get it from your NDK. If you need a specific version of the NDK for your app, you pick it in AGP and it gets used no matter what your dependencies used (aside from some ABI compatibility checking).
DanAlbert commentedon Jan 5, 2022
Coincidentally found the answer in a different bug: https://issuetracker.google.com/issues/141758241#comment23. I think using
pickFromwith your project should resolve the packaging?tanersener commentedon Jan 7, 2022
Does this mean that I will not have the
cannot locate symbol "__emutls_get_address"error if I follow the following steps?r23bforffmpeg-kitand put inffmpeg-kit.aarffmpeg-kit.aar(with prefab) andreact-native.aar(without prefab) as dependenciesndkVersiontor23bin AGPWell, I don't remember I've seen the
pickFromoption before. Had a look at AGP 4.1, AGP 4.2 and AGP 7.0 docs but I don't see it there too. I guess it was a suggestion to address the issue. I'll be happy to use it they decide to implement it.DanAlbert commentedon Jan 7, 2022
It shouldn't matter what NDK is used to build your dependencies as long as its output is ABI compatible (which means everything since r11 is valid, not that I'd recommend using anything that old 😄). If all your dependencies are prefab AARs they don't bundle libc++ and your libc++ will be used regardless of what they built with.
If that's the package that's giving you the out of date copy of libc++ (seems so), if this is still a non-prefab import, this won't fix anything. I should probably mention that I have no clue how react native works so maybe this suggestion is completely off base.
From what I can tell the problem here is that react native is forcing an older (incompatibly older) libc++ into your APK. libffmpegkit is built correctly, it just requires a newer libc++. I don't think any changes to libffmpegkit will help you. I think the fixes available to you (aside from react native rebuilding with r23c) are:
1 isn't really a solution. It might make the problem asymptomatic in some cases, but there's nothing unique about libc++ here that's causing the problem. If you had any other r23c+ built dependency that used thread locals, the problem would still be present. Hiding it in everything would solve that, but that was the cause of #1551. If TLS variables in a shared library need to be usable outside that library,
__emutls_get_addressmust not be hidden in either library because otherwise there are multiple definitions of the function, and therefore multiple addresses for the thread local variable.2 seems ideal, but I came to the same conclusion you did: there's currently no way to describe this requirement to AGP. I'm going to ask around and see if I can get a better answer on that. The advice we (both AGP and NDK teams) have been giving is that file conflicts like these cannot be automatically resolved and the developer must make the decision of which file gets packaged, so I'm pretty surprised to find that it's not possible to actually do that.
I'm pretty frustrated by this bug too, fwiw. There don't seem to many good options for a fix local to apps or the NDK. We'll keep thinking about it.
DanAlbert commentedon Oct 19, 2022
https://issuetracker.google.com/214395989 is the API described by 2. We obviously didn't think up any fixes that we could ship from our side :\
tanersener commentedon Oct 20, 2022
Looks good. Thanks for your help on this Dan! I really appreciate it.