项目原本使用gnustl_shared作为ndk的C++运行时库,没有该问题。考虑官方将会在NDK r18版本移除gnustl,于是项目将C++运行时库切换到c++_shared,在Android 5及以下机型测试过程中,发现dynamic_pointer_cast始终返回nullptr的问题。
原因分析:用于dynamic_pointer_cast转化的类对象定义、创建和使用是在不同的so库中进行的,这个通过readelf -sW xxx.so|grep "yyy"(Android NDK里面也有改程序,ndk-bundle\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin>arm-linux-androideabi-readelf.exe -sW xxx.so|findstr "yyy")可以看到该符号是WEAK DEFAULT,这样就无法正常在libc++里面动态转型,而gnustl对改符号的判断较宽松,判断符号字符串相等即可转化,libc++则还需要判断符号地址。
解决方案:参考ndk官方issue,通过给跨库定义的类增加非内联非纯虚的虚函数(key function)实现(特别注意要实现在cpp文件,因头文件会被编译器优化成内联函数),这时再用readelf可以看到符号变成了GLOBAL DEFAULT,这时便可以正常跨库使用dynamic_pointer_cast转化
参考:
https://github.com/android-ndk/ndk/issues/519 about dynamic_pointer_cast fail
https://github.com/android-ndk/ndk/issues/533 about dynamic_pointer_cast fail
http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vague-vtable libc++ ABI key function
https://codeday.me/bug/20180215/131966.html elf符号列含义