1bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/* 2bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Copyright (C) 2012 The Android Open Source Project 3bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 4bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License"); 5bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * you may not use this file except in compliance with the License. 6bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * You may obtain a copy of the License at 7bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 8bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * http://www.apache.org/licenses/LICENSE-2.0 9bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 10bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Unless required by applicable law or agreed to in writing, software 11bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS, 12bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * See the License for the specific language governing permissions and 14bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * limitations under the License. 15bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 16bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 17bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotpackage com.android.test.runner; 18bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 19bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport dalvik.system.DexFile; 20bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 21bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.IOException; 22bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Enumeration; 23bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.HashSet; 24bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.LinkedHashSet; 25bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Set; 26bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 27bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/** 28bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Finds class entries in apks. 29bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * <p/> 30bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Adapted from tools/tradefederation/..ClassPathScanner 31bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 32bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotclass ClassPathScanner { 33bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 34bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 35bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A filter for classpath entry paths 36bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * <p/> 37bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Patterned after {@link java.io.FileFilter} 38bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 39bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static interface ClassNameFilter { 40bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 41bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Tests whether or not the specified abstract pathname should be included in a class path 42bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * entry list. 43bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 44bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @param pathName the relative path of the class path entry 45bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 46bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot boolean accept(String className); 47bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 48bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 49bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 50bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that accepts all class names. 51bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 52bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class AcceptAllFilter implements ClassNameFilter { 53bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 54bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 55bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 56bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 57bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 58bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String className) { 59bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return true; 60bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 61bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 62bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 63bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 64bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 65bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that chains one or more filters together 66bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 67bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class ChainedClassNameFilter implements ClassNameFilter { 68bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private final ClassNameFilter[] mFilters; 69bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 70bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public ChainedClassNameFilter(ClassNameFilter... filters) { 71bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mFilters = filters; 72bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 73bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 74bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 75bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 76bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 77bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 78bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String className) { 79bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot for (ClassNameFilter filter : mFilters) { 80bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (!filter.accept(className)) { 81bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return false; 82bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 83bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 84bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return true; 85bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 86bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 87bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 88bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 89bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that rejects inner classes. 90bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 91bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class ExternalClassNameFilter implements ClassNameFilter { 92bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 93bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 94bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 95bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 96bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String pathName) { 97bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return !pathName.contains("$"); 98bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 99bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 100bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 101bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 102bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that only accepts package names within the given namespace. 103bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 104bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class InclusivePackageNameFilter implements ClassNameFilter { 105bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 106bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private final String mPkgName; 107bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 108bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot InclusivePackageNameFilter(String pkgName) { 109bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (!pkgName.endsWith(".")) { 110bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = String.format("%s.", pkgName); 111bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } else { 112bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = pkgName; 113bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 114bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 115bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 116bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 117bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 118bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 119bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 120bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String pathName) { 121bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return pathName.startsWith(mPkgName); 122bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 123bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 124bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 125bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 126bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that only rejects a given package names within the given namespace. 127bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 128bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class ExcludePackageNameFilter implements ClassNameFilter { 129bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 130bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private final String mPkgName; 131bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 132bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot ExcludePackageNameFilter(String pkgName) { 133bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (!pkgName.endsWith(".")) { 134bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = String.format("%s.", pkgName); 135bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } else { 136bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = pkgName; 137bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 138bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 139bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 140bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 141bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 142bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 143bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 144bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String pathName) { 145bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return !pathName.startsWith(mPkgName); 146bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 147bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 148bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 149bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private Set<String> mApkPaths = new HashSet<String>(); 150bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 151bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public ClassPathScanner(String... apkPaths) { 152bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot for (String apkPath : apkPaths) { 153bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mApkPaths.add(apkPath); 154bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 155bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 156bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 157bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 158bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Gets the names of all entries contained in given apk file, that match given filter. 159bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @throws IOException 160bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 161bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private void addEntriesFromApk(Set<String> entryNames, String apkPath, ClassNameFilter filter) 162bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot throws IOException { 163bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot DexFile dexFile = null; 164bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot try { 165bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot dexFile = new DexFile(apkPath); 166bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Enumeration<String> apkClassNames = getDexEntries(dexFile); 167bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot while (apkClassNames.hasMoreElements()) { 168bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot String apkClassName = apkClassNames.nextElement(); 169bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (filter.accept(apkClassName)) { 170bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot entryNames.add(apkClassName); 171bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 172bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 173bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } finally { 174bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (dexFile != null) { 175bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot dexFile.close(); 176bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 177bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 178bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 179bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 180bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 181bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Retrieves the entry names from given {@link DexFile}. 182bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * <p/> 183bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Exposed for unit testing. 184bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 185bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @param dexFile 186bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @return {@link Enumeration} of {@link String}s 187bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 188bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Enumeration<String> getDexEntries(DexFile dexFile) { 189bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return dexFile.entries(); 190bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 191bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 192bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 193bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Retrieves set of classpath entries that match given {@link ClassNameFilter}. 194bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @throws IOException 195bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 196bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public Set<String> getClassPathEntries(ClassNameFilter filter) throws IOException { 197bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot // use LinkedHashSet for predictable order 198bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Set<String> entryNames = new LinkedHashSet<String>(); 199bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot for (String apkPath : mApkPaths) { 200bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot addEntriesFromApk(entryNames, apkPath, filter); 201bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 202bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return entryNames; 203bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 204bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot} 205