aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2023-12-14 14:35:41 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-12-14 14:35:41 +0000
commit43b580bb9d699b36e6f6435761129f1ea0d48ead (patch)
tree9b08138b519e324fb84a9ea521d599e5647e66c2
parent4f18c238ed0c32d3e1981b07c0a8d19c35faaead (diff)
parenta35edb190ec2f9054f04ae2bd43d5cb7824c1673 (diff)
downloadgoogle-smali-43b580bb9d699b36e6f6435761129f1ea0d48ead.tar.gz
Support V41 container dex for reading (only) am: ec829c1159 am: a35edb190e
Original change: https://android-review.googlesource.com/c/platform/external/google-smali/+/2873357 Change-Id: I6e885d41b8d8bdf30013ccacae7d3b3fbcfe9f65 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java89
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java93
2 files changed, 81 insertions, 101 deletions
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 653fb5db..7ea7c699 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) {
@@ -122,50 +132,12 @@ public class DexBackedDexFile implements DexFile {
hiddenApiRestrictionsOffset = DexWriter.NO_OFFSET;
}
+ int container_off = 0;
if (dexVersion >= 41) {
- // Reject non-trivial dex container (i.e. multiples dex files in the same physical file).
- int container_off = dexBuffer.readSmallUint(HeaderItem.CONTAINER_OFF_OFFSET);
- int container_size = dexBuffer.readSmallUint(HeaderItem.CONTAINER_SIZE_OFFSET);
- int file_size = dexBuffer.readSmallUint(HeaderItem.FILE_SIZE_OFFSET);
- if (container_off != 0 || container_size != file_size) {
- throw new DexUtil.UnsupportedFile(String.format("Dex container is not supported"));
- }
+ container_off = dexBuffer.readSmallUint(header_offset + HeaderItem.CONTAINER_OFF_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;
- }
-
- 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"));
}
}
@@ -177,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 78c01786..ae8688fc 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>();
ZipFile zipFile = getZipFile();
try {
Enumeration<? extends ZipEntry> entriesEnumeration = zipFile.entries();
@@ -87,10 +98,21 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
continue;
}
- entryNames.add(entry.getName());
+ // There might be several dex files in zip entry since DEX v41.
+ InputStream inputStream = zipFile.getInputStream(entry);
+ try {
+ 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();
+ };
+ } finally {
+ inputStream.close();
+ }
}
- return entryNames;
+ return entries;
} finally {
zipFile.close();
}
@@ -104,17 +126,26 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
* @throws NotADexFile If the entry isn't a dex file
*/
@Nullable @Override public DexEntry<DexBackedDexFile> getEntry(@Nonnull String entryName) throws IOException {
- ZipFile zipFile = getZipFile();
- try {
- ZipEntry entry = zipFile.getEntry(entryName);
- if (entry == null) {
- return null;
- }
-
- return loadEntry(zipFile, entry);
- } finally {
- zipFile.close();
- }
+ DexFile dexFile = getEntries().get(entryName);
+ 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() {
@@ -161,36 +192,6 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
}
}
- @Nonnull
- protected DexEntry loadEntry(@Nonnull ZipFile zipFile, @Nonnull ZipEntry zipEntry) throws IOException {
- InputStream inputStream = zipFile.getInputStream(zipEntry);
- try {
- byte[] buf = ByteStreams.toByteArray(inputStream);
-
- return new DexEntry() {
- @Nonnull
- @Override
- public String getEntryName() {
- return zipEntry.getName();
- }
-
- @Nonnull
- @Override
- public DexFile getDexFile() {
- return new DexBackedDexFile(opcodes, buf);
- }
-
- @Nonnull
- @Override
- public MultiDexContainer getContainer() {
- return ZipDexContainer.this;
- }
- };
- } finally {
- inputStream.close();
- }
- }
-
public static class NotAZipFileException extends RuntimeException {
}
}