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; 22442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabotimport java.util.ArrayList; 23442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabotimport java.util.Arrays; 24bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Enumeration; 25bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.HashSet; 26bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.LinkedHashSet; 27442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabotimport java.util.List; 28bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Set; 29bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 30bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/** 31bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Finds class entries in apks. 32bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * <p/> 33bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Adapted from tools/tradefederation/..ClassPathScanner 34bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 35bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotclass ClassPathScanner { 36bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 37bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 38bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A filter for classpath entry paths 39bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * <p/> 40bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Patterned after {@link java.io.FileFilter} 41bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 42bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static interface ClassNameFilter { 43bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 44bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Tests whether or not the specified abstract pathname should be included in a class path 45bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * entry list. 46bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 47bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @param pathName the relative path of the class path entry 48bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 49bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot boolean accept(String className); 50bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 51bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 52bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 53bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that accepts all class names. 54bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 55bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class AcceptAllFilter implements ClassNameFilter { 56bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 57bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 58bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 59bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 60bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 61bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String className) { 62bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return true; 63bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 64bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 65bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 66bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 67bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 68bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that chains one or more filters together 69bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 70bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class ChainedClassNameFilter implements ClassNameFilter { 71442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot private final List<ClassNameFilter> mFilters = new ArrayList<ClassNameFilter>(); 72bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 73442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot public void add(ClassNameFilter filter) { 74442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot mFilters.add(filter); 75442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot } 76442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot 77442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot public void addAll(ClassNameFilter... filters) { 78442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot mFilters.addAll(Arrays.asList(filters)); 79bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 80bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 81bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 82bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 83bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 84bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 85bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String className) { 86bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot for (ClassNameFilter filter : mFilters) { 87bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (!filter.accept(className)) { 88bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return false; 89bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 90bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 91bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return true; 92bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 93bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 94bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 95bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 96bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that rejects inner classes. 97bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 98bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class ExternalClassNameFilter implements ClassNameFilter { 99bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 100bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 101bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 102bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 103bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String pathName) { 104bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return !pathName.contains("$"); 105bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 106bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 107bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 108bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 109bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that only accepts package names within the given namespace. 110bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 111bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class InclusivePackageNameFilter implements ClassNameFilter { 112bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 113bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private final String mPkgName; 114bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 115bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot InclusivePackageNameFilter(String pkgName) { 116bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (!pkgName.endsWith(".")) { 117bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = String.format("%s.", pkgName); 118bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } else { 119bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = pkgName; 120bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 121bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 122bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 123bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 124bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 125bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 126bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 127bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String pathName) { 128bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return pathName.startsWith(mPkgName); 129bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 130bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 131bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 132bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 133bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * A {@link ClassNameFilter} that only rejects a given package names within the given namespace. 134bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 135bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public static class ExcludePackageNameFilter implements ClassNameFilter { 136bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 137bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private final String mPkgName; 138bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 139bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot ExcludePackageNameFilter(String pkgName) { 140bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (!pkgName.endsWith(".")) { 141bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = String.format("%s.", pkgName); 142bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } else { 143bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mPkgName = pkgName; 144bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 145bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 146bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 147bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 148bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * {@inheritDoc} 149bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 150bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot @Override 151bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public boolean accept(String pathName) { 152bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return !pathName.startsWith(mPkgName); 153bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 154bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 155bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 156bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private Set<String> mApkPaths = new HashSet<String>(); 157bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 158bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public ClassPathScanner(String... apkPaths) { 159bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot for (String apkPath : apkPaths) { 160bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mApkPaths.add(apkPath); 161bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 162bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 163bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 164bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 165bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Gets the names of all entries contained in given apk file, that match given filter. 166bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @throws IOException 167bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 168bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private void addEntriesFromApk(Set<String> entryNames, String apkPath, ClassNameFilter filter) 169bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot throws IOException { 170bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot DexFile dexFile = null; 171bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot try { 172bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot dexFile = new DexFile(apkPath); 173bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Enumeration<String> apkClassNames = getDexEntries(dexFile); 174bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot while (apkClassNames.hasMoreElements()) { 175bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot String apkClassName = apkClassNames.nextElement(); 176bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (filter.accept(apkClassName)) { 177bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot entryNames.add(apkClassName); 178bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 179bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 180bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } finally { 181bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot if (dexFile != null) { 182bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot dexFile.close(); 183bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 184bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 185bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 186bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 187bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 188bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Retrieves the entry names from given {@link DexFile}. 189bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * <p/> 190bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Exposed for unit testing. 191bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 192bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @param dexFile 193bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @return {@link Enumeration} of {@link String}s 194bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 195bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Enumeration<String> getDexEntries(DexFile dexFile) { 196bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return dexFile.entries(); 197bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 198bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 199bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 200bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Retrieves set of classpath entries that match given {@link ClassNameFilter}. 201bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * @throws IOException 202bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 203bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public Set<String> getClassPathEntries(ClassNameFilter filter) throws IOException { 204bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot // use LinkedHashSet for predictable order 205bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Set<String> entryNames = new LinkedHashSet<String>(); 206bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot for (String apkPath : mApkPaths) { 207bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot addEntriesFromApk(entryNames, apkPath, filter); 208bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 209bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return entryNames; 210bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 211bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot} 212