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