diff options
Diffstat (limited to 'dexlib2')
5 files changed, 156 insertions, 94 deletions
diff --git a/dexlib2/Android.bp b/dexlib2/Android.bp new file mode 100644 index 00000000..5be7f1cd --- /dev/null +++ b/dexlib2/Android.bp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + java_library_host { + name: "smali-dexlib2", + + srcs: [ + "src/main/java/**/*.java", + ":third_party-smali-dexlib2", + ], + + static_libs: [ + "guava", + "jsr305", + ], +} + +java_library_host { + name: "smali-dexlib2-no-guava", + + srcs: [ + "src/main/java/**/*.java", + ":third_party-smali-dexlib2", + ], + + libs: [ + "guava", + ], + + static_libs: [ + "jsr305", + ], +}
\ No newline at end of file diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java index 5809e6d4..cbc6db25 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java @@ -43,22 +43,39 @@ public class VersionMap { return 27; case 39: return 28; + case 40: + return 34; + case 41: + return 35; default: return NO_VERSION; } } public static int mapApiToDexVersion(int api) { - if (api <= 23) { + if (api <= 23) { // Android M/6 return 35; } - if (api <= 25) { - return 37; - } - if (api <= 27) { - return 38; + switch (api) { + case 24: // Android N/7 + case 25: // Android N/7.1 + return 37; + case 26: // Android O/8 + case 27: // Android O/8.1 + return 38; + case 28: // Android P/9 + return 39; + case 29: // Android Q/10 + case 30: // Android R/11 + case 31: // Android S/12 + case 32: // Android S/12.1 + case 33: // Android T/13 + case 34: // Android U/14 + return 40; + case 35: // Android V/15 + return 41; } - return 39; + return NO_VERSION; } public static int mapArtVersionToApi(int artVersion) { diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java index 243ff472..c52970f2 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java @@ -74,6 +74,7 @@ public class DexBackedDexFile implements DexFile { @Nonnull private final Opcodes opcodes; + private final int fileSize; private final int stringCount; private final int stringStartOffset; private final int typeCount; @@ -90,6 +91,14 @@ public class DexBackedDexFile implements DexFile { private final int hiddenApiRestrictionsOffset; protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) { + this(opcodes, buf, offset, verifyMagic, 0); + } + + protected DexBackedDexFile(@Nullable Opcodes opcodes, + @Nonnull byte[] buf, + int offset, + boolean verifyMagic, + int header_offset) { dexBuffer = new DexBuffer(buf, offset); dataBuffer = new DexBuffer(buf, offset + getBaseDataOffset()); @@ -101,19 +110,20 @@ public class DexBackedDexFile implements DexFile { this.opcodes = opcodes; } - stringCount = dexBuffer.readSmallUint(HeaderItem.STRING_COUNT_OFFSET); - stringStartOffset = dexBuffer.readSmallUint(HeaderItem.STRING_START_OFFSET); - typeCount = dexBuffer.readSmallUint(HeaderItem.TYPE_COUNT_OFFSET); - typeStartOffset = dexBuffer.readSmallUint(HeaderItem.TYPE_START_OFFSET); - protoCount = dexBuffer.readSmallUint(HeaderItem.PROTO_COUNT_OFFSET); - protoStartOffset = dexBuffer.readSmallUint(HeaderItem.PROTO_START_OFFSET); - fieldCount = dexBuffer.readSmallUint(HeaderItem.FIELD_COUNT_OFFSET); - fieldStartOffset = dexBuffer.readSmallUint(HeaderItem.FIELD_START_OFFSET); - methodCount = dexBuffer.readSmallUint(HeaderItem.METHOD_COUNT_OFFSET); - methodStartOffset = dexBuffer.readSmallUint(HeaderItem.METHOD_START_OFFSET); - classCount = dexBuffer.readSmallUint(HeaderItem.CLASS_COUNT_OFFSET); - classStartOffset = dexBuffer.readSmallUint(HeaderItem.CLASS_START_OFFSET); - mapOffset = dexBuffer.readSmallUint(HeaderItem.MAP_OFFSET); + fileSize = dexBuffer.readSmallUint(header_offset + HeaderItem.FILE_SIZE_OFFSET); + stringCount = dexBuffer.readSmallUint(header_offset + HeaderItem.STRING_COUNT_OFFSET); + stringStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.STRING_START_OFFSET); + typeCount = dexBuffer.readSmallUint(header_offset + HeaderItem.TYPE_COUNT_OFFSET); + typeStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.TYPE_START_OFFSET); + protoCount = dexBuffer.readSmallUint(header_offset + HeaderItem.PROTO_COUNT_OFFSET); + protoStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.PROTO_START_OFFSET); + fieldCount = dexBuffer.readSmallUint(header_offset + HeaderItem.FIELD_COUNT_OFFSET); + fieldStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.FIELD_START_OFFSET); + methodCount = dexBuffer.readSmallUint(header_offset + HeaderItem.METHOD_COUNT_OFFSET); + methodStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.METHOD_START_OFFSET); + classCount = dexBuffer.readSmallUint(header_offset + HeaderItem.CLASS_COUNT_OFFSET); + classStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.CLASS_START_OFFSET); + mapOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.MAP_OFFSET); MapItem mapItem = getMapItemForSection(ItemType.HIDDENAPI_CLASS_DATA_ITEM); if (mapItem != null) { @@ -121,41 +131,13 @@ public class DexBackedDexFile implements DexFile { } else { hiddenApiRestrictionsOffset = DexWriter.NO_OFFSET; } - } - - protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull DexBuffer dexBuffer, @Nonnull DexBuffer dataBuffer, int offset, boolean verifyMagic) { - this.dexBuffer = dexBuffer; - this.dataBuffer = dataBuffer; - - byte[] headerBuf = dexBuffer.readByteRange(offset, HeaderItem.ITEM_SIZE); - - int dexVersion = getVersion(headerBuf, offset, verifyMagic); - if (opcodes == null) { - this.opcodes = getDefaultOpcodes(dexVersion); - } else { - this.opcodes = opcodes; + int container_off = 0; + if (dexVersion >= 41) { + container_off = dexBuffer.readSmallUint(header_offset + HeaderItem.CONTAINER_OFF_OFFSET); } - - stringCount = dexBuffer.readSmallUint(HeaderItem.STRING_COUNT_OFFSET); - stringStartOffset = dexBuffer.readSmallUint(HeaderItem.STRING_START_OFFSET); - typeCount = dexBuffer.readSmallUint(HeaderItem.TYPE_COUNT_OFFSET); - typeStartOffset = dexBuffer.readSmallUint(HeaderItem.TYPE_START_OFFSET); - protoCount = dexBuffer.readSmallUint(HeaderItem.PROTO_COUNT_OFFSET); - protoStartOffset = dexBuffer.readSmallUint(HeaderItem.PROTO_START_OFFSET); - fieldCount = dexBuffer.readSmallUint(HeaderItem.FIELD_COUNT_OFFSET); - fieldStartOffset = dexBuffer.readSmallUint(HeaderItem.FIELD_START_OFFSET); - methodCount = dexBuffer.readSmallUint(HeaderItem.METHOD_COUNT_OFFSET); - methodStartOffset = dexBuffer.readSmallUint(HeaderItem.METHOD_START_OFFSET); - classCount = dexBuffer.readSmallUint(HeaderItem.CLASS_COUNT_OFFSET); - classStartOffset = dexBuffer.readSmallUint(HeaderItem.CLASS_START_OFFSET); - mapOffset = dexBuffer.readSmallUint(HeaderItem.MAP_OFFSET); - - MapItem mapItem = getMapItemForSection(ItemType.HIDDENAPI_CLASS_DATA_ITEM); - if (mapItem != null) { - hiddenApiRestrictionsOffset = mapItem.getOffset(); - } else { - hiddenApiRestrictionsOffset = DexWriter.NO_OFFSET; + if (container_off != header_offset) { + throw new DexUtil.InvalidFile(String.format("Unexpected container offset in header")); } } @@ -167,6 +149,13 @@ public class DexBackedDexFile implements DexFile { return 0; } + /** + * @return Size of single dex file (out of potentially several dex files within a container). + */ + public int getFileSize() { + return fileSize; + } + protected int getVersion(byte[] buf, int offset, boolean verifyMagic) { if (verifyMagic) { return DexUtil.verifyDexHeader(buf, offset); diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java index 0ede09a8..22ccaf8c 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java @@ -40,16 +40,19 @@ import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile.NotADexFile; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import java.util.Map; +import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * Represents a zip file that contains dex files (i.e. an apk or jar file) @@ -58,6 +61,7 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> { private final File zipFilePath; @Nullable private final Opcodes opcodes; + private TreeMap<String, DexBackedDexFile> entries; /** * Constructs a new ZipDexContainer for the given zip file @@ -75,7 +79,14 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> { * @return A list of the names of dex files in this zip file */ @Nonnull @Override public List<String> getDexEntryNames() throws IOException { - List<String> entryNames = Lists.newArrayList(); + return new ArrayList<>(getEntries().keySet()); + } + + private Map<String, DexBackedDexFile> getEntries() throws IOException { + if (entries != null) { + return entries; + } + entries = new TreeMap<String, DexBackedDexFile>(); try (ZipFile zipFile = getZipFile()) { Enumeration<? extends ZipEntry> entriesEnumeration = zipFile.entries(); @@ -86,10 +97,18 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> { continue; } - entryNames.add(entry.getName()); + // There might be several dex files in zip entry since DEX v41. + try (InputStream inputStream = zipFile.getInputStream(entry)) { + byte[] buf = ByteStreams.toByteArray(inputStream); + for (int offset = 0, i = 1; offset < buf.length; i++) { + DexBackedDexFile dex = new DexBackedDexFile(opcodes, buf, 0, true, offset); + entries.put(entry.getName() + (i > 1 ? ("/" + i) : ""), dex); + offset += dex.getFileSize(); + }; + } } - return entryNames; + return entries; } } @@ -97,18 +116,33 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> { * Loads a dex file from a specific named entry. * * @param entryName The name of the entry - * @return A ZipDexFile, or null if there is no entry with the given name + * @return A DexEntry, or null if there is no entry with the given name * @throws NotADexFile If the entry isn't a dex file */ @Nullable @Override public DexEntry<DexBackedDexFile> getEntry(@Nonnull String entryName) throws IOException { - try (ZipFile zipFile = getZipFile()) { - ZipEntry entry = zipFile.getEntry(entryName); - if (entry == null) { - return null; - } - - return loadEntry(zipFile, entry); - } + DexFile dexFile = getEntries().get(entryName); + if (dexFile == null) { + return null; + } + return new DexEntry() { + @Nonnull + @Override + public String getEntryName() { + return entryName; + } + + @Nonnull + @Override + public DexFile getDexFile() { + return dexFile; + } + + @Nonnull + @Override + public MultiDexContainer getContainer() { + return ZipDexContainer.this; + } + }; } public boolean isZipFile() { @@ -143,33 +177,6 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> { } } - @Nonnull - protected DexEntry<DexBackedDexFile> loadEntry(@Nonnull ZipFile zipFile, @Nonnull ZipEntry zipEntry) throws IOException { - try (InputStream inputStream = zipFile.getInputStream(zipEntry)) { - byte[] buf = ByteStreams.toByteArray(inputStream); - - return new DexEntry<DexBackedDexFile>() { - @Nonnull - @Override - public String getEntryName() { - return zipEntry.getName(); - } - - @Nonnull - @Override - public DexBackedDexFile getDexFile() { - return new DexBackedDexFile(opcodes, buf); - } - - @Nonnull - @Override - public MultiDexContainer<DexBackedDexFile> getContainer() { - return ZipDexContainer.this; - } - }; - } - } - public static class NotAZipFileException extends RuntimeException { } } diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java index 61cc0f39..56bb992f 100644 --- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java +++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java @@ -87,6 +87,9 @@ public class HeaderItem { public static final int DATA_SIZE_OFFSET = 104; public static final int DATA_START_OFFSET = 108; + public static final int CONTAINER_SIZE_OFFSET = 112; + public static final int CONTAINER_OFF_OFFSET = 116; + @Nonnull private DexBackedDexFile dexFile; public HeaderItem(@Nonnull DexBackedDexFile dexFile) { |