ndk学习9: 动态使用共享库
动态使用共享库函数
dll_main
环境介绍
续上节代码
目录结构:

android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := demo
LOCAL_SRC_FILES := mod1.cpp mod2.cpp mod3.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Hello
LOCAL_SRC_FILES := Hello.cpp
include $(BUILD_EXECUTABLE)
Hello.cpp
#include <stdio.h>
#include <dlfcn.h>
typedef void (*FUNTYPE)();
int main(int argc, char* argv[])
{
//加载共享库
void *handle = dlopen("/data/local/tmp/libdemo.so", RTLD_NOW);
if (handle == NULL)
{
puts(dlerror());
return 0;
}
printf("handle=%p\n", handle);
//获取导出函数
FUNTYPE pfnMod = (FUNTYPE)dlsym(handle, "_Z4mod1v");
if (pfnMod != NULL)
{
printf("address=%p\n", pfnMod);
pfnMod();
}
pfnMod = (FUNTYPE)dlsym(handle, "_Z4mod2v");
if (pfnMod != NULL)
{
printf("address=%p\n", pfnMod);
pfnMod();
}
pfnMod = (FUNTYPE)dlsym(handle, "_Z4mod3v");
if (pfnMod != NULL)
{
printf("address=%p\n", pfnMod);
pfnMod();
}
pfnMod = (FUNTYPE)dlsym(handle, "mod4");
if (pfnMod == NULL)
{
puts(dlerror());
}
dlclose(handle);
return 0;
}
_Z4mod2v 是C++的名称粉碎
函数名可以用readelf来进行查看:
该工具在: E:\Android\android-ndk-r10b\toolchains\x86-4.6\prebuilt\windows-x86_64\bin\i686-linux-android-readelf.exe

类似于Windows动态调用dll的思想
dlopen打开一个so文件
dlsym根据函数名拿到函数指针
编译后使用makefile执行
在工程目录根下新建makefile:
MODALE_NAME := Hello
# x86 path
X86_TOOLS_PATH :=E:\Android\android-ndk-r10b\toolchains\x86-4.6\prebuilt\windows-x86_64\bin
X86_GDB_PATH := $(X86_TOOLS_PATH)\i686-linux-android-gdb.exe
X86_GDB_SERVER := E:\Android\android-ndk-r10b\prebuilt\android-x86\gdbserver\gdbserver
# arm-linux-androideabi-4.6 path
arm_tools_path :=E:\Android\android-ndk-r10b\toolchains\arm-linux-androideabi-4.6\prebuilt\windows-x86_64\bin
arm_4_6_path := $(arm_tools_path)\arm-linux-androideabi-gdb.exe
arm_gdb_server :=E:\Android\android-ndk-r10b\prebuilt\android-arm\gdbserver\gdbserver
run_arm:
adb push .\libs\armeabi-v7a\$(MODALE_NAME) /data/local/tmp
adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)
adb shell /data/local/tmp/$(MODALE_NAME)
run_x86:
adb push .\libs\x86\$(MODALE_NAME) /data/local/tmp
adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)
adb shell /data/local/tmp/$(MODALE_NAME)
run_x86_share:
adb push .\libs\x86\$(MODALE_NAME) /data/local/tmp
adb push .\libs\x86\libdemo.so /data/local/tmp
adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)
adb shell /data/local/tmp/$(MODALE_NAME)
debug_x86:
adb forward tcp:12345 tcp:12345
adb push $(X86_GDB_SERVER) /data/local/tmp
adb shell chmod 777 /data/local/tmp/gdbserver
adb push .\obj\local\x86\$(MODALE_NAME) /data/local/tmp
adb shell chmod 777 /data/local/tmp/$(MODALE_NAME)
adb shell /data/local/tmp/gdbserver :12345 /data/local/tmp/$(MODALE_NAME)
client_x86:
$(X86_GDB_PATH) .\obj\local\x86\$(MODALE_NAME)
# 1. target remote localhost:12345
# 2. gdb.setup
make run_x86_share 即可成功执行

mod4 会提示找不到
DLL_MAIN
修改mod1.cpp
#include <stdio.h>
// 初始化函数
void _init()
{
printf("_init\r\n");
}
// so卸载函数
void _fini()
{
printf("_fini\r\n");
}
// 新版本初始化函数
void __attribute__((constructor)) OnLoad()
{
printf("OnLoad\r\n");
}
void __attribute__((destructor)) UnLoad()
{
printf("UnLoad\r\n");
}
void __attribute__((constructor)) OnLoad2()
{
printf("OnLoad2\r\n");
}
void __attribute__((destructor)) UnLoad2()
{
printf("UnLoad2\r\n");
}
//隐藏函数
void __attribute__((visibility("hidden"))) mod1()
{
printf("mod1\r\n");
}
运行效果:

说明:
1. _init函数比构造函数来的早
2. hidden后在用dlsym函数无法找到
总结:
1.相关函数
dlopen()函数打开一个共享库
dlsym()函数在库中搜索一个符号
dlclose() 函数光比之前dlopen打开的库
dlerror() 函数返回一个错误消息的字符串
2.隐藏函数
Void __attribute__ ((visibility("hidden"))) fun() {}
3. so构造析构(会在so加载和卸载的时候调用)
void __attribute__ ((constructor)) Load()
void __attribute__ ((destructor)) UnLoad()
4. _init()和_fini()函数
会在so加载和卸载时调用
ndk学习9: 动态使用共享库的更多相关文章
- Android NDK 交叉编译C++代码生成.so共享库详细步骤
Android NDK 交叉编译C++代码生成.so共享库详细步骤 Android NDK 调用c++ stl 模板库(修改android.mk文件) 1 在需要调用模板库的文件前包含头文件: ...
- Android JNI和NDK学习(03)--动态方式实现JNI(转)
本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092491.html 前面总结了静态实现JNI的方法,本文介绍如何动态实现J ...
- Linux学习笔记——如何使用共享库交叉编译
0.前言 在较为复杂的项目中会利用到交叉编译得到的共享库(*.so文件).在这样的情况下便会产生下面疑问,比如: [1]交叉编译时的共享库是否须要放置于目标板中,假设须要放置在哪个文件 ...
- Android NDK生成共享库和静态库
Date: 2014-03-14 Title: Compile Android Native Binary And Library Published: true Type: post Tags: A ...
- Android JNI和NDK学习(04)--NDK调试方法(转)
本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092812.html 本文主要介绍在ndk中添加log的方法.然后,我们就可 ...
- ndk学习8: 编译动态库
目录: 手工编译动态库 ndk-build编译动态库(Eclipse环境) 手工编译静态库 老规矩还是先手工操作,知其然并知其所以然 需要用到的核心命令: gcc -g -c -fpic -W ...
- 《CMake实践》笔记三:构建静态库(.a) 与 动态库(.so) 及 如何使用外部共享库和头文件
<CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...
- ndk学习20: jni之OnLoad动态注册函数
一.原理 当在系统中调用System.loadLibrary函数时,该函数会找到对应的动态库, 然后首先试图找到"JNI_OnLoad"函数,如果该函数存在,则调用它 JNI_On ...
- Linux共享库、静态库、动态库详解
1. 介绍 使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用.程序函数库 ...
随机推荐
- MacPorts安装32位动态库
http://superuser.com/questions/63198/install-32-bits-ports-on-snow-leopard
- 数据库实现多站点共享Session
数据库实现多站点共享Session 多站点共享Session有很多方法,多站点共享Session常见的做法有: 使用.net自动的状态服务(Asp.net State Service); 使用.net ...
- Linq使用Group By 1
Linq使用Group By 1 1.简单形式: var q = from p in db.Products group p by p.CategoryID into g select g; 语句描述 ...
- IntelliJ IDEA 当pom.xml更新时,自动加载pom.xml
http://stackoverflow.com/questions/19444471/intellij-idea-how-to-synchronize-project-libraries-with- ...
- Hibernate 查询MatchMode的四种模式
Hibernate 查询MatchMode的四种模式 MatchMode.START:字符串在最前面的位置.相当于"like 'key%'" MatchMode.END:字符串在最 ...
- Java 8 Optional类深度解析
身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法.我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数. ...
- highcharts图表中级入门之xAxis label:X(横)坐标刻度值过长截断多行(换行)显示问题说明
在使用highcharts图表的过程中,总会碰到这样一个很是棘手的问题,横坐标刻度值太长,在不换行显示的情况下显得格外拥挤.虽然针对这一问题是可以对其刻度值进行旋转以此来避开显示拥挤问题[如何让hig ...
- Java实现zip压缩多个文件下载
为了更好的演示,首先创建一个文件实体FileBean,包含了文件路径和文件名称: package com.javaweb.entity; import java.io.Serializable; /* ...
- 【AngularJS】—— 1 初识AngularJs
怀着激动与忐忑的心情,开始了学习AngularJS的旅程,很久之前就听说了这个前端框架,但是由于自己一直没有从事相关的工作,因此也没有进行学习.这次正好学习AngularJS,直接复习一下前端的知识. ...
- JLS(Third Edition) Chapter12 Execution
这一章详细说明在一个program执行时,发生的activities. 它根据JVM和组成program的类.接口.实例的生命周期 组织. 一个JVM从加载一个特定的类并调用它的main方法开始启 ...