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