1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.releaseparser; 18 19 import com.android.cts.releaseparser.ReleaseProto.*; 20 21 import java.io.File; 22 import java.io.RandomAccessFile; 23 import java.util.Arrays; 24 import java.util.logging.Logger; 25 26 // ART file format at art/runtime/image.h 27 public class ArtParser extends FileParser { 28 // The magic values for the ART identification. 29 private static final byte[] ART_MAGIC = {(byte) 'a', (byte) 'r', (byte) 't', (byte) 0x0A}; 30 private static final int HEADER_SIZE = 512; 31 private ArtInfo.Builder mArtInfoBuilder; 32 ArtParser(File file)33 public ArtParser(File file) { 34 super(file); 35 } 36 37 @Override getType()38 public Entry.EntryType getType() { 39 return Entry.EntryType.ART; 40 } 41 42 @Override setAdditionalInfo()43 public void setAdditionalInfo() { 44 getFileEntryBuilder().setArtInfo(getArtInfo()); 45 } 46 47 @Override getCodeId()48 public String getCodeId() { 49 if (mArtInfoBuilder == null) { 50 parse(); 51 } 52 return mCodeId; 53 } 54 getArtInfo()55 public ArtInfo getArtInfo() { 56 if (mArtInfoBuilder == null) { 57 parse(); 58 } 59 return mArtInfoBuilder.build(); 60 } 61 parse()62 private void parse() { 63 byte[] buffer = new byte[HEADER_SIZE]; 64 mArtInfoBuilder = ArtInfo.newBuilder(); 65 // ToDo check this 66 int kSectionCount = 11; 67 int kImageMethodsCount = 20; 68 try { 69 RandomAccessFile raFile = new RandomAccessFile(getFile(), "r"); 70 raFile.seek(0); 71 raFile.readFully(buffer, 0, HEADER_SIZE); 72 raFile.close(); 73 74 if (buffer[0] != ART_MAGIC[0] 75 || buffer[1] != ART_MAGIC[1] 76 || buffer[2] != ART_MAGIC[2] 77 || buffer[3] != ART_MAGIC[3]) { 78 String content = new String(buffer); 79 System.err.println("Invalid ART file:" + getFileName() + " " + content); 80 mArtInfoBuilder.setValid(false); 81 return; 82 } 83 84 int offset = 4; 85 mArtInfoBuilder.setVersion(new String(Arrays.copyOfRange(buffer, offset, offset + 4))); 86 offset += 4; 87 mArtInfoBuilder.setImageBegin(getIntLittleEndian(buffer, offset)); 88 offset += 4; 89 mArtInfoBuilder.setImageSize(getIntLittleEndian(buffer, offset)); 90 offset += 4; 91 92 int oatChecksum = getIntLittleEndian(buffer, offset); 93 offset += 4; 94 mArtInfoBuilder.setOatChecksum(oatChecksum); 95 mCodeId = String.format(CODE_ID_FORMAT, oatChecksum); 96 97 mArtInfoBuilder.setOatFileBegin(getIntLittleEndian(buffer, offset)); 98 offset += 4; 99 mArtInfoBuilder.setOatDataBegin(getIntLittleEndian(buffer, offset)); 100 offset += 4; 101 mArtInfoBuilder.setOatDataEnd(getIntLittleEndian(buffer, offset)); 102 offset += 4; 103 mArtInfoBuilder.setOatFileEnd(getIntLittleEndian(buffer, offset)); 104 offset += 4; 105 106 mArtInfoBuilder.setBootImageBegin(getIntLittleEndian(buffer, offset)); 107 offset += 4; 108 mArtInfoBuilder.setBootImageSize(getIntLittleEndian(buffer, offset)); 109 offset += 4; 110 mArtInfoBuilder.setBootOatBegin(getIntLittleEndian(buffer, offset)); 111 offset += 4; 112 mArtInfoBuilder.setBootOatSize(getIntLittleEndian(buffer, offset)); 113 offset += 4; 114 115 mArtInfoBuilder.setPatchDelta(getIntLittleEndian(buffer, offset)); 116 offset += 4; 117 mArtInfoBuilder.setImageRoots(getIntLittleEndian(buffer, offset)); 118 offset += 4; 119 120 mArtInfoBuilder.setPointerSize(getIntLittleEndian(buffer, offset)); 121 offset += 4; 122 mArtInfoBuilder.setCompilePic(getIntLittleEndian(buffer, offset)); 123 offset += 4; 124 125 // Todo check further 126 mArtInfoBuilder.setIsPic(getIntLittleEndian(buffer, offset)); 127 offset += 4; 128 mArtInfoBuilder.setStorageMode(getIntLittleEndian(buffer, offset)); 129 offset += 4; 130 mArtInfoBuilder.setDataSize(getIntLittleEndian(buffer, offset)); 131 132 mArtInfoBuilder.setValid(true); 133 } catch (Exception ex) { 134 System.err.println("Invalid ART file:" + getFileName()); 135 mArtInfoBuilder.setValid(false); 136 } 137 } 138 139 private static final String USAGE_MESSAGE = 140 "Usage: java -jar releaseparser.jar " 141 + ArtParser.class.getCanonicalName() 142 + " [-options <parameter>]...\n" 143 + " to parse APK file meta data\n" 144 + "Options:\n" 145 + "\t-i PATH\t The file path of the file to be parsed.\n" 146 + "\t-of PATH\t The file path of the output file instead of printing to System.out.\n"; 147 main(String[] args)148 public static void main(String[] args) { 149 try { 150 ArgumentParser argParser = new ArgumentParser(args); 151 String fileName = argParser.getParameterElement("i", 0); 152 String outputFileName = argParser.getParameterElement("of", 0); 153 154 File aFile = new File(fileName); 155 ArtParser aParser = new ArtParser(aFile); 156 Entry fileEntry = aParser.getFileEntryBuilder().build(); 157 158 writeTextFormatMessage(outputFileName, fileEntry); 159 } catch (Exception ex) { 160 System.out.println(USAGE_MESSAGE); 161 ex.printStackTrace(); 162 } 163 } 164 getLogger()165 private static Logger getLogger() { 166 return Logger.getLogger(ArtParser.class.getSimpleName()); 167 } 168 } 169