各安卓版本关于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
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 }
其中关键的一部分代码是这个:
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
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是怎么得到的。
/** 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
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:
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:
/** 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
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:
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:
/** 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
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:
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这个属性。
/** List of native library path elements. */
private final Element[] nativeLibraryPathElements;
从这里开始复制
this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, null,
suppressedExceptions);
然后makePathElements:
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改成了这个,其实都一个作用
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:
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:
/** List of native library path elements. */
private final Element[]nativeLibraryPathElements;
怎么赋值的呢:
145 this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories,
146 suppressedExceptions,
147 definingContext);
又进行了改变
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
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:
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(List[File](%5BFile%5D(http://androidxref.com/6.0.1_r10/s?defs=File&project=libcore)) files, File optimizedDirectory,List[IOException](%5BIOException%5D(http://androidxref.com/6.0.1_r10/s?defs=IOException&project=libcore)) 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)