blob: a843cdb64d0d5e082237f324b0da9096c710214c [file]
/*
* Copyright (C) 2018 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.
*/
package com.android.cts.releaseparser;
import com.android.cts.releaseparser.ReleaseProto.*;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.logging.Logger;
// art/runtime/vdex_file.h & vdex_file.cc
public class VdexParser extends FileParser {
// The magic values for the VDEX identification.
private static final byte[] VDEX_MAGIC = {(byte) 'v', (byte) 'd', (byte) 'e', (byte) 'x'};
private static final int HEADER_SIZE = 64;
private VdexInfo.Builder mVdexInfoBuilder;
public VdexParser(File file) {
super(file);
}
@Override
public Entry.EntryType getType() {
return Entry.EntryType.VDEX;
}
@Override
public void setAdditionalInfo() {
getFileEntryBuilder().setVdexInfo(getVdexInfo());
}
@Override
public String getCodeId() {
if (mVdexInfoBuilder == null) {
parse();
}
return mCodeId;
}
public VdexInfo getVdexInfo() {
if (mVdexInfoBuilder == null) {
parse();
}
return mVdexInfoBuilder.build();
}
private void parse() {
byte[] buffer = new byte[HEADER_SIZE];
mVdexInfoBuilder = VdexInfo.newBuilder();
try {
RandomAccessFile raFile = new RandomAccessFile(getFile(), "r");
raFile.seek(0);
raFile.readFully(buffer, 0, HEADER_SIZE);
raFile.close();
// ToDo: this is specific for 019 VerifierDepsVersion. Need to handle changes for older
// versions
if (buffer[0] != VDEX_MAGIC[0]
|| buffer[1] != VDEX_MAGIC[1]
|| buffer[2] != VDEX_MAGIC[2]
|| buffer[3] != VDEX_MAGIC[3]) {
String content = new String(buffer);
System.err.println("Invalid VDEX file:" + getFileName() + " " + content);
throw new IllegalArgumentException("Invalid VDEX MAGIC");
}
int offset = 4;
String version = new String(Arrays.copyOfRange(buffer, offset, offset + 4));
mVdexInfoBuilder.setVerifierDepsVersion(version);
offset += 4;
String dex_section_version = new String(Arrays.copyOfRange(buffer, offset, offset + 4));
mVdexInfoBuilder.setDexSectionVersion(dex_section_version);
offset += 4;
int numberOfDexFiles = getIntLittleEndian(buffer, offset);
mVdexInfoBuilder.setNumberOfDexFiles(numberOfDexFiles);
offset += 4;
mVdexInfoBuilder.setVerifierDepsSize(getIntLittleEndian(buffer, offset));
offset += 4;
// Code Id format: [0xchecksum1],...
StringBuilder codeIdSB = new StringBuilder();
for (int i = 0; i < numberOfDexFiles; i++) {
int checksums = getIntLittleEndian(buffer, offset);
offset += 4;
mVdexInfoBuilder.addChecksums(checksums);
codeIdSB.append(String.format(CODE_ID_FORMAT, checksums));
}
mCodeId = codeIdSB.toString();
for (int i = 0; i < numberOfDexFiles; i++) {
DexSectionHeader.Builder dshBuilder = DexSectionHeader.newBuilder();
dshBuilder.setDexSize(getIntLittleEndian(buffer, offset));
offset += 4;
dshBuilder.setDexSharedDataSize(getIntLittleEndian(buffer, offset));
offset += 4;
dshBuilder.setQuickeningInfoSize(getIntLittleEndian(buffer, offset));
offset += 4;
mVdexInfoBuilder.addDexSectionHeaders(dshBuilder.build());
offset += 4;
}
for (int i = 0; i < numberOfDexFiles; i++) {
int quicken_table_off = getIntLittleEndian(buffer, offset);
offset += 4;
// Todo processing Dex
}
} catch (Exception ex) {
System.err.println("Invalid VDEX file:" + getFileName());
mVdexInfoBuilder.setValid(false);
}
}
private static final String USAGE_MESSAGE =
"Usage: java -jar releaseparser.jar "
+ VdexParser.class.getCanonicalName()
+ " [-options <parameter>]...\n"
+ " to parse VDEX file meta data\n"
+ "Options:\n"
+ "\t-i PATH\t The file path of the file to be parsed.\n"
+ "\t-of PATH\t The file path of the output file instead of printing to System.out.\n";
public static void main(String[] args) {
try {
ArgumentParser argParser = new ArgumentParser(args);
String fileName = argParser.getParameterElement("i", 0);
String outputFileName = argParser.getParameterElement("of", 0);
File aFile = new File(fileName);
VdexParser aParser = new VdexParser(aFile);
Entry fileEntry = aParser.getFileEntryBuilder().build();
writeTextFormatMessage(outputFileName, fileEntry);
} catch (Exception ex) {
System.out.println(USAGE_MESSAGE);
ex.printStackTrace();
}
}
private static Logger getLogger() {
return Logger.getLogger(VdexParser.class.getSimpleName());
}
}