aboutsummaryrefslogtreecommitdiff
path: root/dexlib2
diff options
context:
space:
mode:
Diffstat (limited to 'dexlib2')
-rw-r--r--dexlib2/Android.bp46
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java31
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java81
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java89
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java3
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) {