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.compatibility.common.util.ReadElf;
20 import com.android.cts.releaseparser.ReleaseProto.*;
21 import com.google.protobuf.TextFormat;
22 
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.nio.charset.Charset;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.util.Base64;
31 import java.util.List;
32 
33 public class FileParser {
34     private static final String NO_ID = "";
35     protected static final int READ_BLOCK_SIZE = 1024;
36 
37     // Target File Extensions
38     public static final String APK_EXT_TAG = ".apk";
39     public static final String JAR_EXT_TAG = ".jar";
40     public static final String DEX_EXT_TAG = ".dex";
41     public static final String ODEX_EXT_TAG = ".odex";
42     public static final String VDEX_EXT_TAG = ".vdex";
43     public static final String ART_EXT_TAG = ".art";
44     public static final String OAT_EXT_TAG = ".oat";
45     public static final String SO_EXT_TAG = ".so";
46     public static final String BUILD_PROP_EXT_TAG = "build.prop";
47     public static final String RC_EXT_TAG = ".rc";
48     public static final String XML_EXT_TAG = ".xml";
49     public static final String IMG_EXT_TAG = ".img";
50     public static final String TEST_SUITE_TRADEFED_TAG = "-tradefed.jar";
51     public static final String CONFIG_EXT_TAG = ".config";
52     public static final String ANDROID_MANIFEST_TAG = "AndroidManifest.xml";
53     // Code Id format: [0xchecksum1] [...
54     public static final String CODE_ID_FORMAT = "%x ";
55 
56     protected File mFile;
57     protected String mContentId;
58     protected String mCodeId;
59     protected Entry.Builder mFileEntryBuilder;
60 
getParser(File file)61     public static FileParser getParser(File file) {
62         String fName = file.getName();
63         // Starts with SymbolicLink
64         if (isSymbolicLink(file)) {
65             return new SymbolicLinkParser(file);
66         } else if (fName.endsWith(APK_EXT_TAG)) {
67             return new ApkParser(file);
68         } else if (fName.endsWith(CONFIG_EXT_TAG)) {
69             return new TestModuleConfigParser(file);
70         } else if (fName.endsWith(TEST_SUITE_TRADEFED_TAG)) {
71             return new TestSuiteTradefedParser(file);
72         } else if (fName.endsWith(JAR_EXT_TAG)) {
73             // keeps this after TEST_SUITE_TRADEFED_TAG to avoid missing it
74             return new JarParser(file);
75         } else if (fName.endsWith(SO_EXT_TAG)) {
76             return new SoParser(file);
77         } else if (fName.endsWith(ART_EXT_TAG)) {
78             return new ArtParser(file);
79         } else if (fName.endsWith(OAT_EXT_TAG)) {
80             return new OatParser(file);
81         } else if (fName.endsWith(ODEX_EXT_TAG)) {
82             return new OdexParser(file);
83         } else if (fName.endsWith(VDEX_EXT_TAG)) {
84             return new VdexParser(file);
85         } else if (fName.endsWith(BUILD_PROP_EXT_TAG)) {
86             // ToDo prop.default & etc in system/core/init/property_service.cpp
87             return new BuildPropParser(file);
88         } else if (fName.endsWith(RC_EXT_TAG)) {
89             return new RcParser(file);
90         } else if (fName.endsWith(XML_EXT_TAG)) {
91             return new XmlParser(file);
92         } else if (fName.endsWith(IMG_EXT_TAG)) {
93             return new ImgParser(file);
94         } else if (ReadElf.isElf(file)) {
95             // keeps this in the end as no Exe Ext name
96             return new ExeParser(file);
97         } else {
98             // Common File Parser
99             return new FileParser(file);
100         }
101     }
102 
FileParser(File file)103     FileParser(File file) {
104         mFile = file;
105         mCodeId = NO_ID;
106         mContentId = NO_ID;
107         mFileEntryBuilder = null;
108     }
109 
getFile()110     public File getFile() {
111         return mFile;
112     }
113 
getFileName()114     public String getFileName() {
115         return mFile.getName();
116     }
117 
getFileEntryBuilder()118     public Entry.Builder getFileEntryBuilder() {
119         if (mFileEntryBuilder == null) {
120             parse();
121         }
122         return mFileEntryBuilder;
123     }
124 
getType()125     public Entry.EntryType getType() {
126         return Entry.EntryType.FILE;
127     }
128 
getFileContentId()129     public String getFileContentId() {
130         if (NO_ID.equals(mContentId)) {
131             try {
132                 MessageDigest md = MessageDigest.getInstance("SHA-256");
133                 FileInputStream fis = new FileInputStream(mFile);
134                 byte[] dataBytes = new byte[READ_BLOCK_SIZE];
135                 int nread = 0;
136                 while ((nread = fis.read(dataBytes)) != -1) {
137                     md.update(dataBytes, 0, nread);
138                 }
139                 // Converts to Base64 String
140                 mContentId = Base64.getEncoder().encodeToString(md.digest());
141             } catch (IOException e) {
142                 System.err.println("IOException:" + e.getMessage());
143             } catch (NoSuchAlgorithmException e) {
144                 System.err.println("NoSuchAlgorithmException:" + e.getMessage());
145             }
146         }
147         return mContentId;
148     }
149 
getAbiBits()150     public int getAbiBits() {
151         return 0;
152     }
153 
getAbiArchitecture()154     public String getAbiArchitecture() {
155         return NO_ID;
156     }
157 
getCodeId()158     public String getCodeId() {
159         return mCodeId;
160     }
161 
getDependencies()162     public List<String> getDependencies() {
163         return null;
164     }
165 
getDynamicLoadingDependencies()166     public List<String> getDynamicLoadingDependencies() {
167         return null;
168     }
169 
170     /** For subclass parser to add file type specific info into the entry. */
setAdditionalInfo()171     public void setAdditionalInfo() {}
172 
isSymbolicLink(File f)173     private static boolean isSymbolicLink(File f) {
174         // Assumes 0b files are Symbolic Link
175         return (f.length() == 0);
176     }
177 
getIntLittleEndian(byte[] byteArray, int start)178     public static int getIntLittleEndian(byte[] byteArray, int start) {
179         int answer = 0;
180         // Assume Little-Endian. ToDo: if to care about big-endian
181         for (int i = start + 3; i >= start; --i) {
182             answer = (answer << 8) | (byteArray[i] & 0xff);
183         }
184         return answer;
185     }
186 
writeTextFormatMessage(String outputFileName, Entry fileEntry)187     public static void writeTextFormatMessage(String outputFileName, Entry fileEntry)
188             throws IOException {
189         if (outputFileName != null) {
190             FileOutputStream txtOutput = new FileOutputStream(outputFileName);
191             txtOutput.write(TextFormat.printToString(fileEntry).getBytes(Charset.forName("UTF-8")));
192             txtOutput.flush();
193             txtOutput.close();
194         } else {
195             System.out.println(TextFormat.printToString(fileEntry));
196         }
197     }
198 
parse()199     private void parse() {
200         mFileEntryBuilder = Entry.newBuilder();
201         mFileEntryBuilder.setName(getFileName());
202         mFileEntryBuilder.setSize(getFile().length());
203         mFileEntryBuilder.setContentId(getFileContentId());
204         mFileEntryBuilder.setCodeId(getCodeId());
205         mFileEntryBuilder.setType(getType());
206         setAdditionalInfo();
207     }
208 }
209