from:http://yahoo.unblockwebproxysites.com/browse.php?u=7c5e8404115d2ff96Oi8vdG9ueS1saWZlMjAwMC5zcGFjZXMubGl2ZS5jb20vYmxvZy9jbnMhN0RBNzdFNjA3RjJCMTZCRiE0MjkuZW50cnk%3D&b=1
Andriod 如何添加自定义C++库
目前使用复制模式,把Webkit 目录复制一份,取名为Tunnel ,在其 目录下,分别修改Javascripecore 和webcore 下 的Android.mk
l 修改LOCAL_MODULE 变量,这个变量的作用是为一个库取一个独立的名字,在编译过程中脚本会判断会不会有重 复的库,所以修改一下,分别修改为libtunnelwebcore 和libtunnelkjs ,这样就和原有的库不会有名字冲突。
l 修改LOCAL_COPY_HEADERS_TO 变量,这个变量用于脚本COPY 库 中的头文件的时候用的,修改一下名字,脚本会在out/target/product/generc/obj/include/ 目 录下建立一个“名字”的目录,把指定的头文件Copy 进去。
l 修改webcore 中的LOCAL_STATIC_LIBRARIES 变 量,此变量用户指定需要包含的静态库,这里改成前面的lib tunnelkjs
l 动态库需要指定Map 信息,需要修改build/core/prelink-linux-arm.map 中 的信息。
这个map 文件好像是制定动态库的地址的,在前面注释上面有一些地址范围的信息,注意库 与库之间的间隔数,如果指定不好的话编译的时候会提示说地址空间冲突的问题。另外,注意排序,这里要把数大的放到前面去,按照大小降序排序。
重新编译即可,可以看到在out 目录下面的相对位置会产生刚才添加的静动态库。
2. 应用层添加模式,即在发布的SDK 基础上添加自定义的C++ 库。
此操作的目的就是对于一 个第三方而言,要在自己写的程序中调用自己的C++ 库,并且随着安装部署到Android 的环境中的解决方案。
l 在工程的根目录下,必须有一个lib 目录,在lib 目录下创建一个名字为” armeabi” 子目 录,并将所有用到的so 库文件放到该子目录下。
l Java 编码方式
在Java 中 装载so 库时需要按以下方法进行:
a). 使用方法System.load() , 该方法需要使用绝对的路径。
b). 绝对路径为 /data/data/”packageName”/lib/libXXX.so
packageName: 是调用方法System.load() 的java 类所在包的名字。
libXXX.so: 是所要装载的so 库 的名字。
l APK 打包
在对应用进行打包时,需要将前提条件中的lib 目录打进最终的apk 包中,打包后的apk 包结构为:
注:在这个过程中使用的是 ant 进行的工程构建。
3. 过程分析
这部分对分析的过程进行简单的记录,如果只需要知道如何将so 动态库随apk 一起部署,该部分对你没有任何帮 助。
过程涉及两个方面:一方面是apk 的打包,这方面涉及到的工具是apkbuilder( 这 个工具实际上是一个脚本文件,它最终调用了程序apkbuilder.jar) 。另一方面是android 对apk 包的解析部分。
下面描述一个安装apk 包 的过程。
4. 在HostOS 中通过命令安装一个APK 包:adb install xxx.apk
ADB 的概述:
在hostOS 的工具集中有一个工具adb 。在第一次运行adb 命令时,adb 会fork 出一个子进程作为运行在hostOS 中的一个服务,我们将它称为ADB-Server , 将运行命令的adb 称为adb-commandline-tool 。 每次我们在命令提示符中运行adb 时都是运行adb-commandline-tool , 而后adb-commandline-tool 通过本地套接口链接到ADB-Server ,并将命令行中的参数传递给ADB-Server 。
在targetOS 启动时,会启动一个守护进程ADBD 。ADB-Server 启动时会链接到targetOS 中的ADBD 。在ADB-Server 接收到adb-commandline-tool 传 递来的参数后,通过套接口将参数传递给ADBD 。然后ADBD 根 据参数在targetOS 执行不同的命令。
ADBD 接收到ADB-Server 发 送来的数据后,最终调用函数handle_packet() 。
针对”adb install xxx.apk” 命令handle_packet() 的调用过程如下:
handle_packet() |
create_local_service_socket(name) // name: pm xxx.apk |
service_to_fd(name) // name: pm xxx.apk |
create_subprocess(SHELL_COMMAND, "-c", name + 6); |
execl(cmd, cmd, arg0, arg1, NULL); //cmd: "/system/bin/sh" // arg0: -c // arg1: install xxx.apk // 注: 此处的 xxx.apk 是 targetOS 上的路径和文件名。 |
由1 的分析得知最终调用了pm 工具。pm 就是package mamanger ,它是一脚本文件
内容如下:
base=/system export CLASSPATH=$base/framework/pm.jar exec app_process $base/bin com.android.commands.pm.Pm "$@" |
给脚本实际上调用了工具 app_process ,并传递了四个参数:
参数1: /system/bin
参数2 : com.android.commands.pm.Pm
参数3 : -c
参数4 : install xxx.apk
下面来考量 app_process 的调用流程,只是粗略的记录了分析的过程。 App_process 源文件在frameworks/base/cmds/app_process/app_main.cpp 中。