(OK) android源码环境内置已编译好的模块apk_so_jar_bin


http://blog.csdn.net/sgmenghuo/article/details/52238933


0、前言

    作为android开发人员,经常面对这样的问题:网上下载的apk预制到系统,第三方oem提供编译好的库或者jar包等,你要将这些编制到你的系统中该如何做,那么这就不得不要去熟悉android编译环境,即一系列以LOCAL_XXX这样的变量。其实我们实际上碰到的编译MODULE就那么几样,下面我一一列出,可能不全面但是够用了。

1、第三方jar静态编译

    源码环境使用第三方jar,需要关注三个LOCAL_XXX:
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES值格式为  别名:库相对路径
LOCAL_STATIC_JAVA_LIBRARIES
BUILD_MULTI_PREBUILT第三方包,编译类型为BUILD_MULTI_PREBUILT
其中zxing-1.6-core.jar放在apk源码目录的libs目录下
Android.mk如下:
  1. LOCAL_PATH :=$(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE_TAGS := optional  
  5. #LOCAL_JAVA_LIBRARIES := ScannerAPI  telephony-common telephony-msim   
  6. LOCAL_STATIC_JAVA_LIBRARIES :=zxing android-support-v4 android-support-v13  
  7. LOCAL_SRC_FILES :=$(call all-java-files-under, src)  
  8. LOCAL_PACKAGE_NAME := SetInput2  
  9. LOCAL_CERTIFICATE := platform   #签名为platform  
  10.   
  11.   
  12. include $(BUILD_PACKAGE)  
  13.   
  14.   
  15. include $(CLEAR_VARS)  
  16. LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=zxing:libs/zxing-1.6-core.jar  
  17. include $(BUILD_MULTI_PREBUILT)  

2、可执行程序bin

    比如我们想内置某些已编译好的busybox工具
Android.mk如下:
  1. LOCAL_PATH:= $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE        :busybox  
  5. LOCAL_MODULE_TAGS   :optional  
  6. LOCAL_MODULE_CLASS  :EXECUTABLES  
  7. LOCAL_SRC_FILES     :busybox  
  8. LOCAL_MODULE_PATH   := $(PRODUCT_OUT)/system/xbin  
  9. include $(BUILD_PREBUILT)  

3、不带so的apk

    我在源码环境内置apk时发现有的可以运行,有的不能运行(说缺少lib64下的库),所以我分开说明如何内置这2中apk。
RAR工具解压apk没有lib文件夹的就是不带so的apk,最简单。
Android.mk如下:
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE_TAGS :optional  
  5. LOCAL_MODULE :rsota  
  6. LOCAL_SRC_FILES := $(LOCAL_MODULE).apk  
  7. LOCAL_MODULE_CLASS  :APPS  
  8. LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/app  
  9. LOCAL_CERTIFICATE :platform     
  10. LOCAL_MODULE_SUFFIX := .apk  
  11.   
  12. include $(BUILD_PREBUILT)  


4、带so的apk

    解压apk,发现lib文件夹含有xxx.so就是带so的apk,一般这些so默认是32位的,当前我们使用的大量的设备都是64位cpu,apk一运行就曝出找不到lib64类型的库,我们只需要让他调用apk解压的那些32位的so库就行了。

4.1、so库架构类型

    这里穿插下关于lib下so的一些故事。如下是youku.apk中lib目录下的:
    
从这个图可以看出,这个youku.apk支持3种类型的cpu架构:arm,mips,x86,如果这里只有armeabi,那么是绝对不能正常安装到x86的android设备上的(比如使用x86架构的联想K900,好像还是科比代言,卖的好惨,反正我没看到有人用)。如果要提高多架构兼容,就得放入多架构的库,坏处就是apk好大啊吃手机内存啊,所以X86架构的手机好不好卖不是google决定的啊,是apk广大开发者决定的啊,没软件用,谁屌你,所以X86架构一般只能在几百块的水平打酱油,Windows Phone也是没软件用的例子。话说到这跑题了,我们继续库的类型。lib目录下一般包含着几种类型:armeabi,armeabi-v7a,arm64-v8a,mips,x86。不过我们只关注arm的。
armeabi是普通老的32位arm,armeabi-v7a是带浮点运算及一些高级指令的32位arm,arm64-v8a是近几年A53 A57架构的64位arm,具体渊源见如下文章
armeabi-v7a armeabi arm64-v8a》         http://blog.csdn.net/mao520741111/article/details/50328669
现在市面上的基本都是32位apk,所以你基本看不到arm64-v8a库,但是从android L版本后确实是64位虚拟机了,当然是兼容32位的啦,在64位虚拟机运行当然会默认去运行lib64类型的库,而我们内置带so(内置一般都是32位的so)的apk就是要强制让apk去用现有的32位so,方法如下:

4.2、带so库apk例子

1)解包拿出lib下的armeabi或者armeabi-v7a下的xxx.so(最终内置到系统相对于apk目录的lib/arm下)
2)Android.mk既要内置apk还要copy库
注意预置模块,用到BUILD_PREBUILT

例子一

(apk,so和Android.mk在一个目录下):

  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE_TAGS :optional eng  
  5. LOCAL_MODULE :LiangdusIME  
  6. LOCAL_SRC_FILES := $(LOCAL_MODULE).apk  
  7. LOCAL_MODULE_CLASS  :APPS  
  8. LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app  
  9. LOCAL_CERTIFICATE :platform  
  10. LOCAL_MODULE_SUFFIX := .apk  
  11. include $(BUILD_PREBUILT)  
  12.   
  13. include $(CLEAR_VARS)  
  14. LOCAL_MODULE        :libLDWWIme  
  15. LOCAL_MODULE_CLASS  :SHARED_LIBRARIES  
  16. LOCAL_MODULE_SUFFIX := .so  
  17. LOCAL_MULTILIB      :32  
  18. LOCAL_MODULE_TAGS   :optional  
  19. LOCAL_SRC_FILES     :libLDWWIme.so  
  20. LOCAL_MODULE_PATH   := $(PRODUCT_OUT)/system/priv-app/LiangdusIME/lib/arm  
  21. include $(BUILD_PREBUILT)  


例子一有点缺点,要在$(product).mk中进行如下添加PRODUCT_PACKAGES += LiangdusIME libLDWWIme,在库比较少的时候没问题,多的时候,就比较麻烦了。比如一个apk有10个库,那么Android.mk都要要写10个module,$(product).mk也要写上这10个module名,麻烦死了,按道理就是一个apk,就写一个LOCAL_MODULE,其他的库应该有某种简单办法依赖一起内置,是的确实有那就是BUILD_MULTI_PREBUILT.

例子二

目录结构为
---Android.mk
---SeuicService.apk
---armeabi-v7a
       |---libctp_jni.so
       |---libkeypad_jni.so
---arm64-v8a
       |---libctp_jni.so
       |---libkeypad_jni.so

  1. <span style="font-size:14px;">LOCAL_PATH := $(call my-dir)  
  2.   
  3. #====== so lab =====  
  4. include $(CLEAR_VARS)  
  5. LOCAL_PREBUILT_LIBS :armeabi-v7a/libctp_jni.so  
  6. LOCAL_MULTILIB :32  
  7. LOCAL_MODULE_TAGS :optional  
  8. include $(BUILD_MULTI_PREBUILT)  
  9.   
  10. include $(CLEAR_VARS)  
  11. LOCAL_PREBUILT_LIBS :armeabi-v7a/libkeypad_jni.so  
  12. LOCAL_MULTILIB :32  
  13. LOCAL_MODULE_TAGS :optional  
  14. include $(BUILD_MULTI_PREBUILT)  
  15.   
  16. include $(CLEAR_VARS)  
  17. LOCAL_PREBUILT_LIBS :arm64-v8a/libctp_jni.so  
  18. LOCAL_MULTILIB :64  
  19. LOCAL_MODULE_TAGS :optional  
  20. include $(BUILD_MULTI_PREBUILT)  
  21.   
  22. include $(CLEAR_VARS)  
  23. LOCAL_PREBUILT_LIBS :arm64-v8a/libkeypad_jni.so  
  24. LOCAL_MULTILIB :64  
  25. LOCAL_MODULE_TAGS :optional  
  26. include $(BUILD_MULTI_PREBUILT)  
  27.   
  28. # ====  app ========================  
  29. include $(CLEAR_VARS)  
  30.   
  31. LOCAL_MODULE_TAGS :optional  
  32. LOCAL_MODULE :SeuicService  
  33. LOCAL_MODULE_CLASS :APPS  
  34. LOCAL_CERTIFICATE :PRESIGNED     #预签名过了,不需在签名了  
  35. LOCAL_MODULE_PATH := $(TARGET_OUT)/app  
  36. LOCAL_REQUIRED_MODULES :=         #本模块加入系统,我需要的依赖模块也必须加入  
  37.         libkeypad_jni   
  38.             libctp_jni  
  39. LOCAL_SRC_FILES :SeuicService.apk  
  40.   
  41. include $(BUILD_PREBUILT)</span>  

其中LOCAL_REQUIRED_MODULES表示预置SeuicService这个模块时,会先去执行依赖的模块,就是内置so库。这样执行的结果是SeuicService.apk放到了android系统的system/app下,armeabi-v7a的2个so库内置到了android系统的system/lib/下,arm64-v8a的2个so放到了system/lib64/下,apk不管运行在32还是64位虚拟机都能正常。
例子二的区别是so库谁都能用,例子一的so库只有自己能用。

例子三

目录结构为
---Android.mk
---Chrome.apk
---lib
     |---armeabi-v7a
            |---crazy.libchrome.so
            |---libchrome.1847.114.so
|---crazy.libchrome.align
|---libchrome.1916.122.so
|---libchrome.1916.138.so
|---libchrome.1916.141.so
|---libchrome.1985.122.so
|---libchrome.1985.128.so
|---libchrome.1985.131.so
|---libchrome.1985.135.so
|---libchrome.2062.117.so
|---libchrome.2125.102.so
|---libchrome.2125.114.so
|---libchrome.2171.37.so
|---libchrome.2171.59.so
|---libchromium_android_linker.so
|---libchromeview.so

  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. # ====  app ========================  
  4. include $(CLEAR_VARS)  
  5.   
  6. LOCAL_MODULE_TAGS :optional  
  7. LOCAL_MODULE :Chrome  
  8. LOCAL_MODULE_CLASS :APPS  
  9. LOCAL_CERTIFICATE :PRESIGNED  
  10. LOCAL_MODULE_PATH := $(TARGET_OUT)/app  
  11. LOCAL_POST_PROCESS_COMMAND := $(shell mkdir -p $(LOCAL_MODULE_PATH)/Chrome/lib/arm)   
  12. LOCAL_POST_PROCESS_COMMAND := $(shell cp -r $(LOCAL_PATH)/lib/armeabi-v7a/* $(LOCAL_MODULE_PATH)/Chrome/lib/arm)   
  13. LOCAL_SRC_FILES :Chrome.apk  
  14.   
  15. include $(BUILD_PREBUILT)  

这是自由度最大的的方法,这个LOCAL_POST_PROCESS_COMMAND太厉害了简直为所欲为,因为它所引起的shell命令在make初期搜索Android.mk就执行了(我试过了可以多次加入执行)那个时候连system目录等都还没建立呢,这就是为什么我先mkdir再去cp,不然cp在目录没生成的情况下是失败的,而且注意了不报错。所以这种使用方式,需要你预先知道你要干什么,你得能预料结果,一般我就用mmm编译然后到out目录去验证。

5、源码集成带第三方so,jar的apk

这个是网上找到了
  1. LOCAL_PATH:= $(call my-dir)    
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE_TAGS :optional    
  5. LOCAL_STATIC_JAVA_LIBRARIES :libbaidumapapi    
  6. LOCAL_SRC_FILES := $(call all-subdir-java-files)    
  7. LOCAL_PACKAGE_NAME :MyMaps    
  8. include $(BUILD_PACKAGE)    
  9.   
  10. ##################################################    
  11.   
  12. include $(CLEAR_VARS)    
  13.   
  14. LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=libbaidumapapi:libs/baidumapapi.jar    
  15. LOCAL_PREBUILT_LIBS :=libBMapApiEngine_v1_3_1:libs/armeabi/libBMapApiEngine_v1_3_1.so    
  16. LOCAL_MODULE_TAGS :optional    
  17.   
  18. include $(BUILD_MULTI_PREBUILT)    

6、其他预编译

其他如各种配置文件的拷贝基本都是通过include $(BUILD_PREBUILT)或者include $(BUILD_MULTI_PREBUILT)来完成,比如

include $(CLEAR_VARS)
LOCAL_MODULE := com.seuic.misc.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)

基本就是修改LOCAL_MODULE名字,或者修改LOCAL_MODULE_CLASS(类型检查,临时文件存放等),以及修改LOCAL_MODULE_PATH放到哪。
其中LOCAL_MODULE_CLASS值有:APP,ETC,STATIC_LIBRARIES,EXECUTABLES,JAVA_LIBRARIES,SHARED_LIBRARIES等



另外,Android.mk它也是makefile,不要以为它就是特殊的文件,什么都强制照搬,思维会定在如何去用LOCAL_XXX上面,如果你足够熟悉,你可以更灵活点,当然可能不好看。


顺便提下
1)上面看到LOCAL_MODULE_TAGS := optional都是要在$(PRODUCT).mk中将模块名加入到PRODUCT_PACKAGES中的,否则make不编译别找我。
2)将so提升为系统库,就是对应so放到android系统的system/lib或者system/lib64下,这样系统中任何java文件就有机会通过System.loadLibrary("yyy"); 加载libyyy.so,但是,但但是,这个so不是普通c用的so,是jni格式的so。
3)将jar提升为系统包,就是将jar放到android系统的system/framework下,且添加权限,添加权限有2中方法(假设jar文件名为scanner.jar其java包名为com.seuic.scanner,模块名为scan)。
方法一:在$(PRODUCT).mk中添加PRODUCT_BOOT_JARS+=scan
方法二:在对应的*.rc中追加scanner.jar,用冒号分割,export BOOTCLASSPATH /system/framework/core.jar:scanner.jar,这个基本被方法一替代,不要再使用了,编译会自动展开PRODUCT_BOOT_JARS,在系统的root目录下生成init.environ.rc(内容全是export导出的环境变量)
方法三:这个方法独立性比较好,建议用这个方法。
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <permissions>  
  3.     <library  
  4.         name="com.seuic.scanner"  
  5.         file="/system/framework/scanner.jar"  
  6.      />  
  7. </permissions>  
4)Android如何调用第三方SO库
http://zwz94.blog.163.com/blog/static/3206039520131111101412959/
这篇文章问的还是有点意义的,看看能加深理解

原文地址:https://www.cnblogs.com/ztguang/p/12645086.html