Add initial support for N preview odexes

This commit is contained in:
Ben Gruver 2016-04-12 13:57:45 -07:00
parent bccdc809fa
commit c4948a5c49
2 changed files with 88 additions and 20 deletions

View File

@ -22,3 +22,12 @@ fab6788358dfb64e5c370611ddbbbffab0ed0553 - 67
0747466fca310eedea5fc49e37d54f240a0b3c0f - 69 (re-commit of 54b62480)
501fd635a557645ab05f893c56e1f358e21bab82 - 70
99170c636dfae4908b102347cfe9f92bad1881cc - 71
3cfa4d05afa76e19ca99ec964b535a15c73683f0 - 72
d9786b0e5be23ea0258405165098b4216579209c - 73
- fast class lookup table
a4f1220c1518074db18ca1044e9201492975750b - 74
- bootclasspath list was added
625a64aad13905d8a2454bf3cc0e874487b110d5 - 75
- class offsets moved out to a separate table
919f5536182890d2e03f59b961acf8f7c836ff61 - 74 (revert of 625a64aa)
9bdf108885a27ba05fae8501725649574d7c491b - 75 (re-commit of 625a64aa)

View File

@ -31,6 +31,7 @@
package org.jf.dexlib2.dexbacked;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.dexbacked.OatFile.SymbolTable.Symbol;
@ -38,11 +39,13 @@ import org.jf.dexlib2.dexbacked.raw.HeaderItem;
import org.jf.util.AbstractForwardSequentialList;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@ -54,7 +57,7 @@ public class OatFile extends BaseDexBuffer {
// These are the "known working" versions that I have manually inspected the source for.
// Later version may or may not work, depending on what changed.
private static final int MIN_OAT_VERSION = 56;
private static final int MAX_OAT_VERSION = 71;
private static final int MAX_OAT_VERSION = 75;
public static final int UNSUPPORTED = 0;
public static final int SUPPORTED = 1;
@ -148,6 +151,18 @@ public class OatFile extends BaseDexBuffer {
return UNKNOWN;
}
@Nonnull
public List<String> getBootClassPath() {
if (getOatVersion() < 75) {
return ImmutableList.of();
}
String bcp = oatHeader.getKeyValue("bootclasspath");
if (bcp == null) {
return ImmutableList.of();
}
return Arrays.asList(bcp.split(":"));
}
@Nonnull
public List<OatDexFile> getDexFiles() {
return new AbstractForwardSequentialList<OatDexFile>() {
@ -174,11 +189,21 @@ public class OatFile extends BaseDexBuffer {
offset += 4; // checksum
int dexOffset = readSmallUint(offset) + oatHeader.offset;
int dexOffset = readSmallUint(offset) + oatHeader.headerOffset;
offset += 4;
int classCount = readSmallUint(dexOffset + HeaderItem.CLASS_COUNT_OFFSET);
offset += 4 * classCount;
if (getOatVersion() >= 75) {
offset += 4; // offset to class offsets table
}
if (getOatVersion() >= 73) {
offset += 4; // lookup table offset
}
if (getOatVersion() < 75) {
// prior to 75, the class offsets are included here directly
int classCount = readSmallUint(dexOffset + HeaderItem.CLASS_COUNT_OFFSET);
offset += 4 * classCount;
}
index++;
@ -205,63 +230,97 @@ public class OatFile extends BaseDexBuffer {
return OatFile.this.getOatVersion();
}
public OatFile getOatFile() {
return OatFile.this;
}
@Override public boolean hasOdexOpcodes() {
return true;
}
}
private class OatHeader {
private final int offset;
private final int headerOffset;
public OatHeader(int offset) {
this.offset = offset;
this.headerOffset = offset;
}
public boolean isValid() {
for (int i=0; i<OAT_MAGIC.length; i++) {
if (buf[offset + i] != OAT_MAGIC[i]) {
if (buf[headerOffset + i] != OAT_MAGIC[i]) {
return false;
}
}
for (int i=4; i<7; i++) {
if (buf[offset + i] < '0' || buf[offset + i] > '9') {
if (buf[headerOffset + i] < '0' || buf[headerOffset + i] > '9') {
return false;
}
}
return buf[offset + 7] == 0;
return buf[headerOffset + 7] == 0;
}
public int getVersion() {
return Integer.valueOf(new String(buf, offset + 4, 3));
return Integer.valueOf(new String(buf, headerOffset + 4, 3));
}
public int getDexFileCount() {
return readSmallUint(offset + 20);
return readSmallUint(headerOffset + 20);
}
public int getKeyValueStoreSize() {
int version = getVersion();
if (version < 56) {
if (getVersion() < MIN_OAT_VERSION) {
throw new IllegalStateException("Unsupported oat version");
}
int fieldOffset = 17 * 4;
return readSmallUint(offset + fieldOffset);
return readSmallUint(headerOffset + fieldOffset);
}
public int getHeaderSize() {
int version = getVersion();
if (version >= 56) {
return 18*4 + getKeyValueStoreSize();
} else {
if (getVersion() < MIN_OAT_VERSION) {
throw new IllegalStateException("Unsupported oat version");
}
return 18*4 + getKeyValueStoreSize();
}
@Nullable
public String getKeyValue(@Nonnull String key) {
int size = getKeyValueStoreSize();
int offset = headerOffset + 18 * 4;
int endOffset = offset + size;
while (offset < endOffset) {
int keyStartOffset = offset;
while (offset < endOffset && buf[offset] != '\0') {
offset++;
}
if (offset >= endOffset) {
throw new InvalidOatFileException("Oat file contains truncated key value store");
}
int keyEndOffset = offset;
String k = new String(buf, keyStartOffset, keyEndOffset - keyStartOffset);
if (k.equals(key)) {
int valueStartOffset = ++offset;
while (offset < endOffset && buf[offset] != '\0') {
offset++;
}
if (offset >= endOffset) {
throw new InvalidOatFileException("Oat file contains truncated key value store");
}
int valueEndOffset = offset;
return new String(buf, valueStartOffset, valueEndOffset - valueStartOffset);
}
offset++;
}
return null;
}
public int getDexListStart() {
return offset + getHeaderSize();
return headerOffset + getHeaderSize();
}
}