预置第三方apk到系统中Android.mk, 关于32/64位so库兼容的问题

在使用android 64位的系统时预置第三方apk,而apk中使用的so库为32位,预置到系统中当使用到相应的32位库时报错:java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/system/app/xxxxx/xxxxx.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libxxxx.so"

Android.mk如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := xxxx
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MULTILIB := 32
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_CERTIFICATE := platform
LOCAL_SHARED_LIBRARIES := libUHF_1_2_ModuleAPIJni libUHF_5_module_manager libUHF_5_serial_port libUHF_6_Module_DeviceAPI libUHF_8_SerialPort libUHF_11_ruijie
include $(BUILD_PREBUILT)

include $(CLEAR_VARS)
LOCAL_MULTILIB := 32
LOCAL_CERTIFICATE := platform
LOCAL_PREBUILT_LIBS := libUHF_1_2_ModuleAPIJni:./lib/armeabi/libUHF_1_2_ModuleAPIJni.so libUHF_5_module_manager:./lib/armeabi/libUHF_5_module_manager.so libUHF_5_serial
include $(BUILD_MULTI_PREBUILT)

运行apk时会出报错如下:

E/AndroidRuntime( 2861): java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/system/app/xxxx/xxxx.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libUHF_8_SerialPort.so"
E/AndroidRuntime( 2861): 	at java.lang.Runtime.loadLibrary(Runtime.java:367)
E/AndroidRuntime( 2861): 	at java.lang.System.loadLibrary(System.java:988)
E/AndroidRuntime( 2861): 	at com.cellsnet.serialport.SerialPort.

修改:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := xxxx
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := xxxx.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_PREBUILT_JNI_LIBS:= \
@lib/armeabi/libUHF_1_2_ModuleAPIJni.so \
@lib/armeabi/libUHF_5_module_manager.so        \
@lib/armeabi/libUHF_5_serial_port.so   \
@lib/armeabi/libUHF_6_Module_DeviceAPI.so      \
@lib/armeabi/libUHF_8_SerialPort.so \
@lib/armeabi/libUHF_11_ruijie.so
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MULTILIB :=32
LOCAL_MODULE_PATH := $(TARGET_OUT)/app
LOCAL_SDK_VERSION := current
include $(BUILD_PREBUILT)

注:前面的 @符号,@标识符会将apk中的so抽离出来,拷贝到对应编译后的apk目录

原因分析:
使用LOCAL_SHARED_LIBRARIES LOCAL_MULTILIB := 32加载32位的库编译时能包相应的so库编译到系统的system/lib/下,但由于系统是64位的并且apk内置到system/app/下,所有这个apk默认是使用64位的,所有就会出现如保存的log中,只去放64位库的路径下查找,所有就会出现报错;而使用LOCAL_PREBUILT_JNI_LIBS加载32位库时,会将相应的so文件编译到当前apk的编译目录,而在64位系统中,对于system app如果apk包中lib文件夹下有.so库,就根据这个.so库的架构模式,确定app的primaryCpuAbi的值(使用多少位的架构模式加载)

总结:
    1.如果apk包中lib文件夹下有.so库,就根据这个.so库的架构模式,确定app的primaryCpuAbi的值
    2.对于system app, 如果没法通过第一步确定primaryCpuAbi的值,PKMS会根据/system/app/${APP_NAME}/lib和/system/app/${APP_NAME}/lib64这两个文件夹是否存在,来确定它的primaryCpuAbi的值
    3.对于还没有确定的app, 在最后还会将自己的primaryCpuAbi值与和他使用相同UID的package的值设成一样
    4.对于到这里还没有确认primaryCpuAbi的app,就会在启动进程时使用ro.product.cpu.abilist这个property的值的第一项作为它关联的ABI

 

关于android.mk中LOCAL_PREBUILT_JNI_LIBS使用方法:

方法一 不从apk中解压lib库而直接添加
如下例,在Android.mk中添加并配置变量(注意路径对应):
LOCAL_PREBUILT_JNI_LIBS = \
@lib/armeabi-v7a/libcryptox.so \
@lib/armeabi-v7a/libfb.so
注意前面的 @符号,@标识符会将apk中的so抽离出来,拷贝到对应编译后的apk目录;

方法二 手动解压lib文件到当前apk的编译目录并添加
先解压当前apk内的lib文件夹到当前apk编译目录,同方法一在Android.mk中添加并配置变量(注意路径对应),如下例:
LOCAL_PREBUILT_JNI_LIBS = \
lib/armeabi-v7a/libcryptox.so \
lib/armeabi-v7a/libfb.so

若当前apk包含的lib库文件数量比较多时,上述代码可以通过修改为如下代码进行优化,优化的思路是用递归搜索来替代手工对lib库文件进行添加:
###清空临时变量JNI_LIBS
JNI_LIBS :=
###当前目录递归搜索
$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))
###获取搜索文件目录集(相对目录)
LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))

你可能感兴趣的:(android)