通过NDK在Android上加载不同版本的系统共享库?

通过NDK在Android上加载不同版本的系统共享库?,android,android-ndk,shared-libraries,skia,Android,Android Ndk,Shared Libraries,Skia,我正在尝试使用一些本机库来开发android应用程序。但是,android 4.0和android 4.1.2上的系统共享库是不同的。为了确保兼容性,我从平台4.0获取libskia.so文件,并将其导入到我的项目中。我希望像使用第三方共享库一样加载此共享库。不幸的是,在安卓4.1.2上运行时,我的应用程序似乎仍然调用系统skia库。我对此一无所知,以下是我的Android.mk文件 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL

我正在尝试使用一些本机库来开发android应用程序。但是,
android 4.0
android 4.1.2
上的系统共享库是不同的。为了确保兼容性,我从平台4.0获取libskia.so文件,并将其导入到我的项目中。我希望像使用第三方共享库一样加载此共享库。不幸的是,在安卓4.1.2上运行时,我的应用程序似乎仍然调用系统skia库。我对此一无所知,以下是我的
Android.mk
文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := sample
LOCAL_SRC_FILES := sample-jni.cpp

LOCAL_CFLAGS    := -I /home/WORKING_DIRECTORY/external/skia/include \
-I /home/WORKING_DIRECTORY/external/skia/include/core \
-I /home/WORKING_DIRECTORY/frameworks/base/core/jni/android/graphics  \
-I /home/WORKING_DIRECTORY/frameworks/base/include \
-I /home/WORKING_DIRECTORY/frameworks/base/native/include/android \
-I /home/WORKING_DIRECTORY/system/core/include \
-I /home/WORKING_DIRECTORY/external/skia/include/xml \
-I /home/WORKING_DIRECTORY/external/skia/include/images \
-I /home/WORKING_DIRECTORY/external/skia/include/views \

 LOCAL_SHARED_LIBRARIES :=skia jnigraphics
 include $(BUILD_SHARED_LIBRARY)
 include $(LOCAL_PATH)/prebuilt/Android.mk
以及预构建的makefile

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := skia
LOCAL_SRC_FILES := libskia.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := jnigraphics
LOCAL_SRC_FILES := libjnigraphics.so
include $(PREBUILT_SHARED_LIBRARY)

有什么想法吗?或者,是否有其他方法来确保兼容性?

我希望您理解,不建议您对系统库的依赖性超出范围。但Android的开放性(技术上和许可方面)允许引入这种依赖性。本质上,这意味着在非特许水域航行,并准备好不仅在平台的下一版本中,而且在相同平台级别的供应商提供的(即非AOSP)设置中进行API更改

理论上,您可以将系统库变体的副本放入应用程序的libs/armeabi-v7a文件夹中,并使用而不是loadLibrary()加载它

但实际上,我相信system/lib/libskia.so将在您有机会执行代码之前加载到您的进程中,并且您不能在同一进程中加载同一lib的两个版本。另外,旧版本的libskia很可能无法加载到系统上,因为它依赖于其他系统库

确保向前(和供应商)兼容性的最安全方法是使用未记录的系统功能,并在途中仔细执行错误检查

但在许多情况下,系统中未记录的API实际上相当稳定,谷歌安卓团队中的好人不会经常做出破坏性的更改。因此,如果您链接到4.0版的skia,您的代码很可能只在4.1.2和


<强> Update:在特定的情况下,当一个额外的字段<代码> fTraceLaLe>/Cuff>被添加到一个旧的类中时,首先应该祝福那些没有在类声明中间插入这个字段的开发人员。因为现在您有了一个合理的策略:使用4.1.2头文件(带有额外的字段),链接4.0库(不向新字段引入访问器方法),您的代码有望正常工作。

您可以通过在本地代码中使用带有参数RTLD_DEEPBIND的dlopen来使用不同版本的libskia。这将覆盖全局符号表。

谢谢!我想我理解依赖不稳定API的风险,但需求迫使我使用这些未记录的特性。我不能完全理解你提到的
动态链接的方式。当我链接到skia的4.0版本时,由于某些函数的不同实现,我的应用程序总是在4.1.2上崩溃。如果您在4.1.2上遇到崩溃,您可以调试它们。您可以下载4.1.2版skia库的源代码,甚至整个平台的源代码。但首先,我会尝试从4.1.2设备中提取libskia.so,并尝试与之链接。当与4.1.2版本的库链接时,应用程序是否仍会以同样的方式在4.1.2上崩溃?当与4.1.2版本的skia链接时,它运行良好。我已经下载了这两个平台的源代码,我确实发现在我的应用程序经常崩溃的功能中有一些变化。在这种情况下,我应该从android源代码树构建一个特定版本的静态skia库吗?我相信这将是可行的,但也需要更大的努力。如果你能分享更多关于功能和更改的信息,我将不胜感激。没有这一点,我就不能给你一个有根据的建议。名为
fTextLocale
的新成员变量在平台4.1.2的SkPaint.h中声明,该变量在4.0中不存在,SkPaint的构造函数将使用该变量。因此,当我链接到4.0版的skia并运行一个简单的
SkPaint代码时
在android 4.1.2上,应用程序崩溃,因为在lib 4.0.Jeff中找不到symbol
fTextLocale
,理论上这是正确的。但在实践中,
dlopen()
不是正确的选择。首先,
/system/lib/libskia.so
可能是在APK有机会加载自定义
libsample.so之前加载到流程中的。其次,旧版本的
libskia.so
可能会查找其他系统库的错误版本,并且无法加载。第三,用<代码> dLScript()/>代码代替所有代码调用C++代码API。