public static DexFile[] getOdexFromOat(Oat oat, Opcodes opcodes) throws IOException { final int BSIZE = 8192; final byte[] buf = new byte[BSIZE]; if (opcodes == null) { opcodes = new Opcodes(oat.guessApiLevel()); } DexFile[] dexFiles = new DexFile[oat.mOatDexFiles.length]; for (int i = 0; i < oat.mOatDexFiles.length; i++) { Oat.DexFile dex = oat.mDexFiles[i]; final int dexSize = dex.mHeader.file_size_; dexFiles[i] = readDex(dex, dexSize, opcodes, buf); } return dexFiles; }
private static void convertToDex( Oat oat, File outputFolder, String bootClassPath, boolean addSelfToBcp) throws IOException { final Opcodes opcodes = new Opcodes(oat.guessApiLevel()); LLog.i("Preparing bootclasspath from " + bootClassPath); if (bootClassPath == null || !new File(bootClassPath).exists()) { LLog.e("Invalid bootclasspath: " + bootClassPath); } final OatDexRewriterModule odr = new OatDexRewriterModule(bootClassPath, opcodes); final DexRewriter deOpt = odr.getRewriter(); DexFile[] dexFiles = getOdexFromOat(oat, opcodes); if (addSelfToBcp) { for (DexFile d : dexFiles) { odr.mBootClassPath.addDex(d); } } for (int i = 0; i < oat.mOatDexFiles.length; i++) { Oat.OatDexFile odf = oat.mOatDexFiles[i]; String dexLoc = new String(odf.dex_file_location_data_); String opath = getOuputNameForSubDex(dexLoc); if ("base.apk".equals(opath)) { opath = MiscUtil.getFilenamePrefix(oat.mSrcFile.getName()); } File outputFile = MiscUtil.changeExt(new File(outputFolder, opath), "dex"); LLog.i("De-optimizing " + dexLoc); DexFile d = deOpt.rewriteDexFile(dexFiles[i]); if (!OatDexRewriter.isValid(d)) { LLog.i("convertToDex: skip " + dexLoc); continue; } if (outputFile.exists()) { File old = outputFile; outputFile = MiscUtil.appendTail(outputFile, "-deodex"); LLog.i(old + " already existed, use name " + outputFile.getName()); } DexPool.writeTo(outputFile.getAbsolutePath(), d); LLog.i("Output to " + outputFile); } }
public static void convertToDexJar( Oat oat, File outputFolder, String bootClassPath, String noClassJarFolder, boolean isBoot) throws IOException { final Opcodes opcodes = new Opcodes(oat.guessApiLevel()); LLog.i("Preparing bootclasspath from " + bootClassPath); final OatDexRewriterModule odr = new OatDexRewriterModule(bootClassPath, opcodes); HashMap<String, ArrayList<Oat.DexFile>> dexFileGroup = new HashMap<>(); for (int i = 0; i < oat.mOatDexFiles.length; i++) { Oat.OatDexFile odf = oat.mOatDexFiles[i]; String opath = new String(odf.dex_file_location_data_); int spos = opath.indexOf(':'); if (spos > 0) { // .../framework.jar:classes2.dex opath = opath.substring(0, spos); } opath = opath.substring(opath.lastIndexOf('/') + 1); ArrayList<Oat.DexFile> dfiles = dexFileGroup.get(opath); if (dfiles == null) { dfiles = new ArrayList<>(); dexFileGroup.put(opath, dfiles); } dfiles.add(oat.mDexFiles[i]); if (!isBoot) { Oat.DexFile dex = oat.mDexFiles[i]; odr.mBootClassPath.addDex(readDex(dex, dex.mHeader.file_size_, opcodes, null)); } } final int BSIZE = 8192; final byte[] buf = new byte[BSIZE]; final DexRewriter deOpt = odr.getRewriter(); for (String jarName : dexFileGroup.keySet()) { File outputFile = MiscUtil.changeExt(new File(outputFolder, jarName), "jar"); String classesIdx = ""; int i = 1; int readSize; try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(outputFile))) { for (Oat.DexFile dex : dexFileGroup.get(jarName)) { jos.putNextEntry(new ZipEntry("classes" + classesIdx + ".dex")); final int dexSize = dex.mHeader.file_size_; ByteBuffer dexBytes = ByteBuffer.allocateDirect(dexSize); dex.mReader.seek(dex.mDexPosition); int remain = dexSize; int read = BSIZE > dexSize ? dexSize : BSIZE; while ((readSize = dex.mReader.readRaw(buf, 0, read)) != -1 && remain > 0) { dexBytes.put(buf, 0, readSize); remain -= readSize; if (remain < BSIZE) { read = remain; } } LLog.i("De-optimizing " + jarName + (i > 1 ? (" part-" + classesIdx) : "")); int length = dexBytes.position(); dexBytes.flip(); byte[] data = new byte[length]; dexBytes.get(data); DexFile d = new DexBackedDexFile(opcodes, data); d = deOpt.rewriteDexFile(d); if (!OatDexRewriter.isValid(d)) { LLog.i("convertToDexJar: skip " + jarName); continue; } MemoryDataStore m = new MemoryDataStore(dexSize + 512); DexPool.writeTo(m, d); jos.write(m.mBuffer.mData, 0, m.mBuffer.mMaxDataPosition); classesIdx = String.valueOf(++i); jos.closeEntry(); } // Copy files from original jar try (JarFile jarFile = new JarFile(new File(noClassJarFolder, jarName))) { final Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { final JarEntry e = entries.nextElement(); String name = e.getName(); if (name.startsWith("classes") && name.endsWith(".dex")) { continue; } jos.putNextEntry(new ZipEntry(name)); try (InputStream is = jarFile.getInputStream(e)) { int bytesRead; while ((bytesRead = is.read(buf)) != -1) { jos.write(buf, 0, bytesRead); } } jos.closeEntry(); } } LLog.i("Output " + outputFile); } catch (IOException e) { LLog.ex(e); } } }