各安卓版本关于loadLibrary函数的实现区别

loadLibrary主要是在Runtime.java中实现,各个版本之间差异比较大,所以做个笔记来整理这些区别。

4.4 版本

源码:

Cross Reference: /libcore/luni/src/main/java/java/lang/Runtime.java

主要是这一块:

http://androidxref.com/4.4.4_r1/xref/libcore/luni/src/main/java/java/lang/Runtime.java#354

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void loadLibrary(String libraryName, ClassLoader loader) {
355 if (loader != null) {
356 String filename = loader.findLibrary(libraryName);
357 if (filename == null) {
358 throw new UnsatisfiedLinkError("Couldn't load " + libraryName +
359 " from loader " + loader +
360 ": findLibrary returned null");
361 }
362 String error = doLoad(filename, loader);
363 if (error != null) {
364 throw new UnsatisfiedLinkError(error);
365 }
366 return;
367 }
368
369 String filename = System.mapLibraryName(libraryName);
370 List<String> candidates = new ArrayList<String>();
371 String lastError = null;
372 for (String directory : mLibPaths) {
373 String candidate = directory + filename;
374 candidates.add(candidate);
375
376 if (IoUtils.canOpenReadOnly(candidate)) {
377 String error = doLoad(candidate, loader);
378 if (error == null) {
379 return; // We successfully loaded the library. Job done.
380 }
381 lastError = error;
382 }
383 }
384
385 if (lastError != null) {
386 throw new UnsatisfiedLinkError(lastError);
387 }
388 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
389 }

其中关键的一部分代码是这个:

1
2
3
4
5
6
String filename = loader.findLibrary(libraryName);
357 if (filename == null) {
358 throw new UnsatisfiedLinkError("Couldn't load " + libraryName +
359 " from loader " + loader +
360 ": findLibrary returned null");
361 }

接着去寻找findLibrary。

http://androidxref.com/4.4.4_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java#380

1
2
3
4
5
6
7
8
9
10
380    public String findLibrary(String libraryName) {
381 String fileName = System.mapLibraryName(libraryName);
382 for (File directory : nativeLibraryDirectories) {
383 String path = new File(directory, fileName).getPath();
384 if (IoUtils.canOpenReadOnly(path)) {
385 return path;
386 }
387 }
388 return null;
389 }

就是将nativeLibraryDirectories变量遍历里面是否包含了要加载的so文件。

来看下nativeLibraryDirectories是怎么得到的。

1
2
/** List of native library directories. */
private final File[]nativeLibraryDirectories;

是一个File[]数组呢,而且是final的。

但是接着看的话,在DexPathList初始化的时候将这个变量进行赋值:

  • this.nativeLibraryDirectories = splitLibraryPath(libraryPath);

5.0版本

源码:

http://androidxref.com/5.0.0_r2/xref/libcore/luni/src/main/java/java/lang/Runtime.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
358    void loadLibrary(String libraryName, ClassLoader loader) {
359 if (loader != null) {
360 String filename = loader.findLibrary(libraryName);
361 if (filename == null) {
362 // It's not necessarily true that the ClassLoader used
363 // System.mapLibraryName, but the default setup does, and it's
364 // misleading to say we didn't find "libMyLibrary.so" when we
365 // actually searched for "liblibMyLibrary.so.so".
366 throw new UnsatisfiedLinkError(loader + " couldn't find \\"" +
367 System.mapLibraryName(libraryName) + "\\"");
368 }
369 String error = doLoad(filename, loader);
370 if (error != null) {
371 throw new UnsatisfiedLinkError(error);
372 }
373 return;
374 }
375
376 String filename = System.mapLibraryName(libraryName);
377 List<String> candidates = new ArrayList<String>();
378 String lastError = null;
379 for (String directory : mLibPaths) {
380 String candidate = directory + filename;
381 candidates.add(candidate);
382
383 if (IoUtils.canOpenReadOnly(candidate)) {
384 String error = doLoad(candidate, loader);
385 if (error == null) {
386 return; // We successfully loaded the library. Job done.
387 }
388 lastError = error;
389 }
390 }
391
392 if (lastError != null) {
393 throw new UnsatisfiedLinkError(lastError);
394 }
395 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
396 }

findLibrary:

1
2
3
4
5
6
7
8
9
10
379    public String findLibrary(String libraryName) {
380 String fileName = System.mapLibraryName(libraryName);
381 for (File directory : nativeLibraryDirectories) {
382 String path = new File(directory, fileName).getPath();
383 if (IoUtils.canOpenReadOnly(path)) {
384 return path;
385 }
386 }
387 return null;
388 }

nativeLibraryDirectories:

1
2
/** List of native library directories. */
private final File[]nativeLibraryDirectories;

也还是File数组且为final。

最后赋值也是跟4.4一样:

  • this.nativeLibraryDirectories = splitLibraryPath(libraryPath);

5.1版本

源码:

http://androidxref.com/5.1.1_r6/xref/libcore/luni/src/main/java/java/lang/Runtime.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
358    void loadLibrary(String libraryName, ClassLoader loader) {
359 if (loader != null) {
360 String filename = loader.findLibrary(libraryName);
361 if (filename == null) {
362 // It's not necessarily true that the ClassLoader used
363 // System.mapLibraryName, but the default setup does, and it's
364 // misleading to say we didn't find "libMyLibrary.so" when we
365 // actually searched for "liblibMyLibrary.so.so".
366 throw new UnsatisfiedLinkError(loader + " couldn't find \\"" +
367 System.mapLibraryName(libraryName) + "\\"");
368 }
369 String error = doLoad(filename, loader);
370 if (error != null) {
371 throw new UnsatisfiedLinkError(error);
372 }
373 return;
374 }
375
376 String filename = System.mapLibraryName(libraryName);
377 List<String> candidates = new ArrayList<String>();
378 String lastError = null;
379 for (String directory : mLibPaths) {
380 String candidate = directory + filename;
381 candidates.add(candidate);
382
383 if (IoUtils.canOpenReadOnly(candidate)) {
384 String error = doLoad(candidate, loader);
385 if (error == null) {
386 return; // We successfully loaded the library. Job done.
387 }
388 lastError = error;
389 }
390 }
391
392 if (lastError != null) {
393 throw new UnsatisfiedLinkError(lastError);
394 }
395 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
396 }

findLibrary:

1
2
3
4
5
6
7
8
9
10
379    public String findLibrary(String libraryName) {
380 String fileName = System.mapLibraryName(libraryName);
381 for (File directory : nativeLibraryDirectories) {
382 String path = new File(directory, fileName).getPath();
383 if (IoUtils.canOpenReadOnly(path)) {
384 return path;
385 }
386 }
387 return null;
388 }

nativeLibraryDirectories:

1
2
/** List of native library directories. */
private final File[] nativeLibraryDirectories;
  • this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
  • private static File[] splitLibraryPath(String path)

6.0版本

源码:

http://androidxref.com/6.0.1_r10/xref/libcore/luni/src/main/java/java/lang/Runtime.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
359    void loadLibrary(String libraryName, ClassLoader loader) {
360 if (loader != null) {
361 String filename = loader.findLibrary(libraryName);
362 if (filename == null) {
363 // It's not necessarily true that the ClassLoader used
364 // System.mapLibraryName, but the default setup does, and it's
365 // misleading to say we didn't find "libMyLibrary.so" when we
366 // actually searched for "liblibMyLibrary.so.so".
367 throw new UnsatisfiedLinkError(loader + " couldn't find \\"" +
368 System.mapLibraryName(libraryName) + "\\"");
369 }
370 String error = doLoad(filename, loader);
371 if (error != null) {
372 throw new UnsatisfiedLinkError(error);
373 }
374 return;
375 }
376
377 String filename = System.mapLibraryName(libraryName);
378 List<String> candidates = new ArrayList<String>();
379 String lastError = null;
380 for (String directory : mLibPaths) {
381 String candidate = directory + filename;
382 candidates.add(candidate);
383
384 if (IoUtils.canOpenReadOnly(candidate)) {
385 String error = doLoad(candidate, loader);
386 if (error == null) {
387 return; // We successfully loaded the library. Job done.
388 }
389 lastError = error;
390 }
391 }
392
393 if (lastError != null) {
394 throw new UnsatisfiedLinkError(lastError);
395 }
396 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
397 }

findLibrary:

1
2
3
4
5
6
7
8
9
10
11
12
13
396    public String findLibrary(String libraryName) {
397 String fileName = System.mapLibraryName(libraryName);
398
399 for (Element element : nativeLibraryPathElements) {
400 String path = element.findNativeLibrary(fileName);
401
402 if (path != null) {
403 return path;
404 }
405 }
406
407 return null;
408 }

nativeLibraryPathElements,从6.0开始好像就有了nativeLibraryPathElements这个属性。

1
2
/** List of native library path elements. */
private final Element[] nativeLibraryPathElements;

从这里开始复制

1
2
this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, null,
suppressedExceptions);

然后makePathElements:

1
private static Element[] makePathElements(List<File>files,File optimizedDirectory,List<IOException>suppressedExceptions)

属性就可以了。

7.0版本

源码:

http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/java/java/lang/Runtime.java

从7.0开始增加了loadLibrary0这个函数,其实就是将之前的loadLibrary改成了这个,其实都一个作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
959    synchronized void loadLibrary0(ClassLoader loader, String libname) {
960 if (libname.indexOf((int)File.separatorChar) != -1) {
961 throw new UnsatisfiedLinkError(
962 "Directory separator should not appear in library name: " + libname);
963 }
964 String libraryName = libname;
965 if (loader != null) {
966 String filename = loader.findLibrary(libraryName);
967 if (filename == null) {
968 // It's not necessarily true that the ClassLoader used
969 // System.mapLibraryName, but the default setup does, and it's
970 // misleading to say we didn't find "libMyLibrary.so" when we
971 // actually searched for "liblibMyLibrary.so.so".
972 throw new UnsatisfiedLinkError(loader + " couldn't find \\"" +
973 System.mapLibraryName(libraryName) + "\\"");
974 }
975 String error = doLoad(filename, loader);
976 if (error != null) {
977 throw new UnsatisfiedLinkError(error);
978 }
979 return;
980 }
981
982 String filename = System.mapLibraryName(libraryName);
983 List<String> candidates = new ArrayList<String>();
984 String lastError = null;
985 for (String directory : getLibPaths()) {
986 String candidate = directory + filename;
987 candidates.add(candidate);
988
989 if (IoUtils.canOpenReadOnly(candidate)) {
990 String error = doLoad(candidate, loader);
991 if (error == null) {
992 return; // We successfully loaded the library. Job done.
993 }
994 lastError = error;
995 }
996 }
997
998 if (lastError != null) {
999 throw new UnsatisfiedLinkError(lastError);
1000 }
1001 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
1002 }

findLibrary:

1
2
3
4
5
6
7
8
9
10
11
12
13
476    public String findLibrary(String libraryName) {
477 String fileName = System.mapLibraryName(libraryName);
478
479 for (Element element : nativeLibraryPathElements) {
480 String path = element.findNativeLibrary(fileName);
481
482 if (path != null) {
483 return path;
484 }
485 }
486
487 return null;
488 }

nativeLibraryPathElements:

1
2
/** List of native library path elements. */
private final Element[]nativeLibraryPathElements;

怎么赋值的呢:

1
2
3
145        this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories,
146 suppressedExceptions,
147 definingContext);

又进行了改变

1
2
3
269    private static Element[] makePathElements(List<File> files,
270 List<IOException> suppressedExceptions,
271 ClassLoader loader)

之前6.0的两个list和一个file,又改成了两个list和一个classloader

7.1跟7.0一样不赘述。

8.0

源码:

http://androidxref.com/8.1.0_r33/xref/libcore/ojluni/src/main/java/java/lang/Runtime.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
998    synchronized void loadLibrary0(ClassLoader loader, String libname) {
999 if (libname.indexOf((int)File.separatorChar) != -1) {
1000 throw new UnsatisfiedLinkError(
1001 "Directory separator should not appear in library name: " + libname);
1002 }
1003 String libraryName = libname;
1004 if (loader != null) {
1005 String filename = loader.findLibrary(libraryName);
1006 if (filename == null) {
1007 // It's not necessarily true that the ClassLoader used
1008 // System.mapLibraryName, but the default setup does, and it's
1009 // misleading to say we didn't find "libMyLibrary.so" when we
1010 // actually searched for "liblibMyLibrary.so.so".
1011 throw new UnsatisfiedLinkError(loader + " couldn't find \\"" +
1012 System.mapLibraryName(libraryName) + "\\"");
1013 }
1014 String error = doLoad(filename, loader);
1015 if (error != null) {
1016 throw new UnsatisfiedLinkError(error);
1017 }
1018 return;
1019 }
1020
1021 String filename = System.mapLibraryName(libraryName);
1022 List<String> candidates = new ArrayList<String>();
1023 String lastError = null;
1024 for (String directory : getLibPaths()) {
1025 String candidate = directory + filename;
1026 candidates.add(candidate);
1027
1028 if (IoUtils.canOpenReadOnly(candidate)) {
1029 String error = doLoad(candidate, loader);
1030 if (error == null) {
1031 return; // We successfully loaded the library. Job done.
1032 }
1033 lastError = error;
1034 }
1035 }
1036
1037 if (lastError != null) {
1038 throw new UnsatisfiedLinkError(lastError);
1039 }
1040 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
1041 }

findLibrary:

1
2
3
4
5
6
7
8
9
10
11
12
13
524    public String findLibrary(String libraryName) {
525 String fileName = System.mapLibraryName(libraryName);
526
527 for (NativeLibraryElement element : nativeLibraryPathElements) {
528 String path = element.findNativeLibrary(fileName);
529
530 if (path != null) {
531 return path;
532 }
533 }
534
535 return null;
536 }

怎么赋值的呢

  • this.nativeLibraryPathElements = makePathElements(this.systemNativeLibraryDirectories);

然后makePathElements:

  • private static NativeLibraryElement[] makePathElements(List files)

返回值改了,参数也改了。

就很纳闷,google这帮人不干实事整天改这个干嘛,有漏洞?

总结

4.4 ~5.1

都是使用的

this.nativeLibraryDirectories = splitLibraryPath(libraryPath);

private static File[] splitLibraryPath(String path)

6.0

this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, null,suppressedExceptions);

private static Element[] makePathElements(ListFile files, File optimizedDirectory,ListIOException suppressedExceptions)

7.0 ~ 7.1

this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, suppressedExceptions, definingContext);

private static Element[] makePathElements(List files, List suppressedExceptions, ClassLoader loader)

8.0 ~ 8.1

this.nativeLibraryPathElements = makePathElements(this.systemNativeLibraryDirectories);

private static NativeLibraryElement[] makePathElements(List files)