安卓源代码来自如下网站
http://androidxref.com/
我就选最新的9.0系统分析了Pie - 9.0.0_r3
这里搜索LoadLibrary,右边select all 勾选上
然后点击Search,可以看到相关当前方法的调用。
在这之前先说一下LoadLibrary方法的用法
LoadLibrary来自System对象,所以调用时,
需要前面加上System,由于是直接调用的,
因此此对象不需要实例化,直接System.loadlibrary,
loadlibrary方法会专门调用apk包中lib文件夹下的so文件,
下面拿一个安卓apk做示范,
这里我用的是360压缩直接打开的,
apk文件结构如下
继续回到安卓系统源码上,搜索后,一个一个看,
看到类似的函数声明
此函数返回值为万能指针,能存放所有数据类型的空间,
第一个方法数据类型为字符型,是调用LoadLibrary函数的
so文件路径,在调用loadLibrary函数时安卓端省略了路径,
省略了lib前缀,省略了.so后缀,例如libLanAn.so
只需要输入System.loadLibrary(“LanAn”),即可,
193 void* (*loadLibrary)(const char* libpath, int flag);
194
195 // Get a native bridge trampoline for specified native method. The trampoline has same
196 // sigature as the native method.
197 //
198 // Parameters:
199 // handle [IN] the handle returned from loadLibrary
200 // shorty [IN] short descriptor of native method
201 // len [IN] length of shorty
202 // Returns:
203 // address of trampoline if successful, otherwise NULL
源码跟踪示例

点进去可以看到如下函数声明,这里只有声明
因此还需继续搜索,
void* (*loadLibrary)(const char* libpath, int flag);
可以试试搜索 void* loadLibrary这个函数
如下是搜索这个函数找到的结果

30void *loadLibrary(const char *(&names)[n], const char *mustContainSymbol = nullptr)
31{
32 for(int i = 0; i < n; i++)
33 {
34 void *library = getLibraryHandle(names[i]);
35
36 if(library)
37 {
38 if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
39 {
40 return library;
41 }
42
43 freeLibrary(library);
44 }
45 }
46
47 for(int i = 0; i < n; i++)
48 {
49 void *library = loadLibrary(names[i]);
50
51 if(library)
52 {
53 if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
54 {
55 return library;
56 }
57
58 freeLibrary(library);
59 }
60 }
61
62 return nullptr;
63}
继续跟踪如下代码
代码意思是获取so文件句柄,没有句柄无法操作so文件
void *library = getLibraryHandle(names[i]);
如下是此函数getLibraryHandle的声明
24void *getLibraryHandle(const char *path);
下面是关键代码
65#if defined(_WIN32)
66 inline void *loadLibrary(const char *path)
67 {
68 return (void*)LoadLibrary(path);
69 }
70
71 inline void *getLibraryHandle(const char *path)
72 {
73 HMODULE module = NULL;
74 GetModuleHandleEx(0, path, &module);
75 return (void*)module;
76 }
77
78 inline void freeLibrary(void *library)
79 {
80 FreeLibrary((HMODULE)library);
81 }
82
83 inline void *getProcAddress(void *library, const char *name)
84 {
85 return (void*)GetProcAddress((HMODULE)library, name);
86 }
87#else
88 inline void *loadLibrary(const char *path)
89 {
90 return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
91 }
92
93 inline void *getLibraryHandle(const char *path)
94 {
95 #ifdef __ANDROID__
96 // bionic doesn't support RTLD_NOLOAD before L
97 return dlopen(path, RTLD_NOW | RTLD_LOCAL);
98 #else
99 void *resident = dlopen(path, RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
100
101 if(resident)
102 {
103 return dlopen(path, RTLD_LAZY | RTLD_LOCAL); // Increment reference count
104 }
105
106 return nullptr;
107 #endif
108 }
109
110 inline void freeLibrary(void *library)
111 {
112 if(library)
113 {
114 dlclose(library);
115 }
116 }
117
118 inline void *getProcAddress(void *library, const char *name)
119 {
120 void *symbol = dlsym(library, name);
121
122 if(!symbol)
123 {
124 const char *reason = dlerror(); // Silence the error
125 (void)reason;
126 }
127
128 return symbol;
129 }
130#endif
继续搜寻,发现该函数的实现
93 inline void *getLibraryHandle(const char *path)
94 {
95 #ifdef __ANDROID__
96 // bionic doesn't support RTLD_NOLOAD before L
97 return dlopen(path, RTLD_NOW | RTLD_LOCAL);
98 #else
99 void *resident = dlopen(path, RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
100
101 if(resident)
102 {
103 return dlopen(path, RTLD_LAZY | RTLD_LOCAL); // Increment reference count
104 }
105
106 return nullptr;
107 #endif
108 }
109
如下代码打开了so文件,并且返回了文件句柄
return dlopen(path, RTLD_NOW | RTLD_LOCAL);
继续跟踪dlopen函数
如下是dlopen函数的实现
void *dlopen(char *filename, int flags)
70/* load a dynamic-link library and return handle */
71void *dlopen(char *filename, int flags)
72{
73 HMODULE hm;
74 DLLchain tmp;
75 char err[256];
76 char *errtxt;
77 int rc = 0, set_chain = 0;
78
79 for (tmp = dlload; tmp; tmp = tmp->next)
80 if (strnicmp(tmp->name, filename, 999) == 0)
81 break;
82
83 if (!tmp)
84 {
85 tmp = (DLLchain) malloc(sizeof(tDLLchain));
86 if (!tmp)
87 goto nomem;
88 tmp->name = strdup(filename);
89 tmp->next = dlload;
90 set_chain = 1;
91 }
92
93 switch (rc = DosLoadModule((PSZ)&err, sizeof(err), filename, &hm))
94 {
95 case NO_ERROR:
96 tmp->handle = hm;
97 if (set_chain)
98 {
99 do
100 last_id++;
101 while ((last_id == 0) || (find_id(last_id)));
102 tmp->id = last_id;
103 dlload = tmp;
104 }
105 return tmp->id;
106 case ERROR_FILE_NOT_FOUND:
107 case ERROR_PATH_NOT_FOUND:
108 errtxt = "module `%s' not found";
109 break;
110 case ERROR_TOO_MANY_OPEN_FILES:
111 case ERROR_NOT_ENOUGH_MEMORY:
112 case ERROR_SHARING_BUFFER_EXCEEDED:
113nomem:
114 errtxt = "out of system resources";
115 break;
116 case ERROR_ACCESS_DENIED:
117 errtxt = "access denied";
118 break;
119 case ERROR_BAD_FORMAT:
120 case ERROR_INVALID_SEGMENT_NUMBER:
121 case ERROR_INVALID_ORDINAL:
122 case ERROR_INVALID_MODULETYPE:
123 case ERROR_INVALID_EXE_SIGNATURE:
124 case ERROR_EXE_MARKED_INVALID:
125 case ERROR_ITERATED_DATA_EXCEEDS_64K:
126 case ERROR_INVALID_MINALLOCSIZE:
127 case ERROR_INVALID_SEGDPL:
128 case ERROR_AUTODATASEG_EXCEEDS_64K:
129 case ERROR_RELOCSRC_CHAIN_EXCEEDS_SEGLIMIT:
130 errtxt = "invalid module format";
131 break;
132 case ERROR_INVALID_NAME:
133 errtxt = "filename doesn't match module name";
134 break;
135 case ERROR_SHARING_VIOLATION:
136 case ERROR_LOCK_VIOLATION:
137 errtxt = "sharing violation";
138 break;
139 case ERROR_INIT_ROUTINE_FAILED:
140 errtxt = "module initialization failed";
141 break;
142 default:
143 errtxt = "cause `%s', error code = %d";
144 break;
145 }
146 snprintf(dlerr, sizeof(dlerr), errtxt, &err, rc);
147 if (tmp)
148 {
149 if (tmp->name)
150 free(tmp->name);
151 free(tmp);
152 }
153 return 0;
154}
这里看关键代码
这里选择跟踪函数参数,filename为so的文件名字,
也是dlopen函数的参数,
如下代码在对比文件名字
80 if (strnicmp(tmp->name, filename, 999) == 0)
81 break;
继续跟踪
这里关键代码为
88 tmp->name = strdup(filename);
83 if (!tmp)
84 {
85 tmp = (DLLchain) malloc(sizeof(tDLLchain));
86 if (!tmp)
87 goto nomem;
88 tmp->name = strdup(filename);
89 tmp->next = dlload;
90 set_chain = 1;
91 }
92
函数声明如下
char *strdup(const char *str)
该函数?在复制字符串,
如下函数把字符串赋值给了tmp空间里面的name参数,
88 tmp->name = strdup(filename);
下面是dlopen代码的最终结束段。
105 return tmp->id;
93 switch (rc = DosLoadModule((PSZ)&err, sizeof(err), filename, &hm))
94 {
95 case NO_ERROR:
96 tmp->handle = hm;
97 if (set_chain)
98 {
99 do
100 last_id++;
101 while ((last_id == 0) || (find_id(last_id)));
102 tmp->id = last_id;
103 dlload = tmp;
104 }
105 return tmp->id;
此函数返回了句柄
DosLoadModule((PSZ)&err, sizeof(err), filename, &hm)
到此分析完毕,
有了句柄就能调用里面的函数了。