android loadlibrary 更改libPath 路径,指定路径加载.so
http://www.jianshu.com/p/f751be55d1fb
- 需求很简单 ,就是加载指定文件夹下的.so。
- 原因:android在程序运行的状态下 ,无法在 data/data/packageName/lib 下写文件,但可读。
- 还有一个引申的问题:data/app-lib/packageName/ 下的.so 和 data/data/packageName/lib 的.so 是什么关系?
1 . 获取全局的classloader
PathClassLoader pathClassLoader = (PathClassLoader)context.getClassLoader();
DexClassLoader myDexClassLoader = new DexClassLoader(str, context.getDir("dex", 0).getAbsolutePath(), str, context.getClassLoader().getParent());
2 . 获取pathList
Object pathList = getPathList(pathClassLoader);
3 . 添加路径
File[] file = new File[]{
new File("/data/app-lib/pakageName-1"),
new File("/data/app-lib/pakageName-2"),
new File("/data/data/pakageName/files"),
new File("/vendor/lib"),
new File("/system/lib")
} ;
4 . 获取当前类的属性
Object nativeLibraryDirectories=pathList.getClass().getDeclaredField("nativeLibraryDirectories");
((Field)nativeLibraryDirectories).setAccessible(true);
5 . 设置新的路径
((Field)nativeLibraryDirectories).set(pathList, file);
6 . 对classloader的操作,对应于BaseDexClassLoader:
public BaseDexClassLoader(String dexPath,File optimizedDirectory,String libraryPath,ClassLoader parent){
super(parent);
this.pathList=new DexPathList(this,dexPath,libraryPath,optimizedDirectory);
}
7 . dex,library路径对应于DexPathList, 这部分和热补丁密切相关,有兴趣可以搜下hotfix ,很多开源项目。
privatefinalElement[]dexElements; //这部分就是dex分包的了,热补丁,热补丁,热补丁
privatefinalFile[]nativeLibraryDirectories;//这部分就是 libs 加载路径了,默认有 /vendor/lib system/lib data/app-lib/packageName
最后给下代码:
public static void initNativeDirectory(Application application) {
if (hasDexClassLoader()) {
try {
createNewNativeDir(application);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void createNewNativeDir(Context context) throws Exception{
PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
Object pathList = getPathList(pathClassLoader);
//获取当前类的属性
Object nativeLibraryDirectories = pathList.getClass().getDeclaredField("nativeLibraryDirectories");
((Field) nativeLibraryDirectories).setAccessible(true);
//获取 DEXPATHList中的属性值
File[] files1 = (File[])((Field) nativeLibraryDirectories).get(pathList);
Object filesss = Array.newInstance(File.class, files1.length + 1);
//添加自定义.so路径
Array.set(filesss, 0, new File(context.getFilesDir().getAbsolutePath()));
//将系统自己的追加上
for(int i = 1;i<files1.length+1;i++){
Array.set(filesss,i,files1[i-1]);
}
// File[] filesss = new File[file.length+ files1.length];
// filesss[0] = file[0];
// for(int i = 1;i < files1.length+1;i++){
// filesss[i] = files1[i];
// }
((Field) nativeLibraryDirectories).set(pathList, filesss);
}
private static Object getPathList(Object obj) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
return getField(obj, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
}
private static Object getField(Object obj, Class cls, String str) throws NoSuchFieldException, IllegalAccessException {
Field declaredField = cls.getDeclaredField(str);
declaredField.setAccessible(true);
return declaredField.get(obj);
}
/**
* 仅对4.0以上做支持
* @return
*/
private static boolean hasDexClassLoader() {
try {
Class.forName("dalvik.system.BaseDexClassLoader");
return true;
} catch (ClassNotFoundException var1) {
return false;
}
}