1 /* 2 * Copyright (C) 2017 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.apicoverage; 18 19 20 import org.xml.sax.SAXException; 21 22 import java.io.File; 23 import java.io.FileOutputStream; 24 import java.io.FilenameFilter; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.util.ArrayList; 28 import java.util.Enumeration; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.zip.ZipEntry; 33 import java.util.zip.ZipFile; 34 /** 35 * Class that outputs an XML report of the {@link ApiCoverage} collected. It can be viewed in a 36 * browser when used with the api-coverage.css and api-coverage.xsl files. 37 */ 38 class ApkNdkApiReport { 39 public static final String FILE_FILTER_EXT = ".apk"; 40 public static final String DEFAULT_OUTPUT_FILE_NAME = "./apk-ndk-coverage.txt"; 41 42 private static final FilenameFilter SUPPORTED_FILE_NAME_FILTER = 43 new FilenameFilter() { 44 public boolean accept(File dir, String name) { 45 String fileName = name.toLowerCase(); 46 return fileName.endsWith(FILE_FILTER_EXT); 47 } 48 }; 49 printUsage()50 private static void printUsage() { 51 System.out.println("Usage: ApkNdkApiReport [OPTION]... [APK]..."); 52 System.out.println(); 53 System.out.println("Generates a report about what Android NDK methods."); 54 System.out.println(); 55 System.out.println("Options:"); 56 System.out.println(" -o FILE output file or standard out if not given"); 57 System.out.println(" -t PATH path to the CTS testcases Folder"); 58 System.out.println(" -b BITS 64 or 32"); 59 System.out.println(); 60 System.exit(1); 61 } 62 63 /** Get the argument or print out the usage and exit. */ getExpectedArg(String[] args, int index)64 private static String getExpectedArg(String[] args, int index) { 65 if (index < args.length) { 66 return args[index]; 67 } else { 68 printUsage(); 69 return null; // Never will happen because printUsage will call exit(1) 70 } 71 } 72 main(String[] args)73 public static void main(String[] args) throws IOException, SAXException { 74 ApkNdkApiReport apiReport; 75 String testCasePath = ""; 76 String bits = "64"; 77 String outputFileName = DEFAULT_OUTPUT_FILE_NAME; 78 int numTestModule = 0; 79 80 for (int i = 0; i < args.length; i++) { 81 if (args[i].startsWith("-")) { 82 if ("-o".equals(args[i])) { 83 outputFileName = getExpectedArg(args, ++i); 84 } else if ("-t".equals(args[i])) { 85 testCasePath = getExpectedArg(args, ++i); 86 } else if ("-b".equals(args[i])) { 87 bits = getExpectedArg(args, ++i); 88 } else { 89 printUsage(); 90 } 91 } else { 92 printUsage(); 93 } 94 } 95 96 apiReport = parseTestcasesFolder(testCasePath, bits); 97 if (apiReport != null) { 98 for (TestModule tm : apiReport.mTestModules) { 99 tm.getDynSymArr(); 100 } 101 } else { 102 printUsage(); 103 } 104 } 105 106 private List<TestModule> mTestModules; 107 private String mBits; 108 ApkNdkApiReport(List<TestModule> testModules, String bits)109 ApkNdkApiReport(List<TestModule> testModules, String bits) { 110 mTestModules = testModules; 111 mBits = bits; 112 } 113 getTestModules()114 public List<TestModule> getTestModules() { 115 return mTestModules; 116 } 117 getBits()118 public String getBits() { 119 return mBits; 120 } 121 parseTestcasesFolder(String testCasePath, String bits)122 public static ApkNdkApiReport parseTestcasesFolder(String testCasePath, String bits) 123 throws IOException, SAXException { 124 File[] testConfigFiles; 125 List<TestModule> testModules = new ArrayList<TestModule>(); 126 127 File file = new File(testCasePath); 128 if (file.isDirectory()) { 129 File[] targetFiles = file.listFiles(SUPPORTED_FILE_NAME_FILTER); 130 131 Map<String, String> env = new HashMap<>(); 132 for (File targetFile : targetFiles) { 133 final ZipFile apkFile = new ZipFile(targetFile); 134 System.out.println(targetFile.getName()); 135 try { 136 final Enumeration<? extends ZipEntry> entries = apkFile.entries(); 137 while (entries.hasMoreElements()) { 138 final ZipEntry entry = entries.nextElement(); 139 140 if (!entry.getName().matches("lib(.*)" + bits + "(.*)so")) { 141 continue; 142 } 143 144 System.out.println(entry.getName()); 145 146 //use entry input stream: 147 InputStream is = apkFile.getInputStream(entry); 148 149 File tempFile = File.createTempFile("ApkNdkApiReport", ".so"); 150 tempFile.deleteOnExit(); 151 FileOutputStream fos = new FileOutputStream(tempFile); 152 153 byte[] bytes = new byte[4096]; 154 int length; 155 while ((length = is.read(bytes)) >= 0) { 156 fos.write(bytes, 0, length); 157 } 158 is.close(); 159 fos.close(); 160 161 testModules.add(new TestModule(tempFile, targetFile.getName(), "jUnit")); 162 } 163 } catch (IOException e) { 164 e.printStackTrace(); 165 } 166 } 167 } else { 168 return null; 169 } 170 return new ApkNdkApiReport(testModules, bits); 171 } 172 } 173