在动态加载dex的时候可能会出现以下问题:
java.lang.IllegalArgumentException: Optimized data directory /storage/emulated/0 is not owned by the current user. Shared storage cannot protect your application from code injection attacks.
原因:
从Android4.1.2开始,App不能直接从sdcard中加载字节码,因为sdcard对于所有应用程序来说是共享的,为了防止恶意的代码注入,当采用DexClassLoader从sdcard中动态加载字节码的时候,就会抛出异常,为了安全,在DexFile下加入了以下代码判断
Libcore.os.getuid() != Libcore.os.stat(parent).st_uid
用来判断两个程序是不是同一个uid
DexFile:
private DexFile(String sourceName, String outputName, int flags) throws IOException {
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid){
throw new IllegalArgumentException("Optimized data directory " + parent
+ " is not owned by the current user. Shared storage cannot protect"
+ " your application from code injection attacks.");
}
} catch (ErrnoException ignored) {
// assume we'll fail with a more contextual error later
}
}
mCookie = openDexFile(sourceName, outputName, flags);
mFileName = sourceName;
guard.open("close");
//System.out.println("DEX FILE cookie is " + mCookie);
}
解决方法:
指定dexoutputpath为APP自己的缓存目录,通过context.getDir(“dex”,0)。作为dex的加载目录。
也就是用app的私有目录,data/data/应用程序包名下创建一个dex目录放置该dex,并作为加载目录。
加入以下代码即可:
File dexOutputDir = context.getDir("dex", 0);
DexClassLoader loader= new DexClassLoader(dexpath, dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader().getParent());