19cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll/*
29cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * Copyright (C) 2009 The Android Open Source Project
39cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll *
49cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * Licensed under the Apache License, Version 2.0 (the "License");
59cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * you may not use this file except in compliance with the License.
69cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * You may obtain a copy of the License at
79cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll *
89cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll *      http://www.apache.org/licenses/LICENSE-2.0
99cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll *
109cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * Unless required by applicable law or agreed to in writing, software
119cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * distributed under the License is distributed on an "AS IS" BASIS,
129cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * See the License for the specific language governing permissions and
149cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll * limitations under the License.
159cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll */
169cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
179cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollpackage com.android.mkstubs;
189cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
198252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphaelimport com.android.mkstubs.Main.Logger;
208252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael
219cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport org.objectweb.asm.ClassReader;
229cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
239cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.io.IOException;
249cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.Enumeration;
259cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.Iterator;
269cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.Map;
279cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.Set;
289cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.TreeMap;
299cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.zip.ZipEntry;
309cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollimport java.util.zip.ZipFile;
319cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
329cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll/**
33adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * Analyzes an input Jar to get all the relevant classes according to the given filter.
34adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * <p/>
35adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * This is mostly a helper extracted for convenience. Callers will want to use
36adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * {@link #parseInputJar(String)} followed by {@link #filter(Map, Filter)}.
379cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll */
389cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Mollclass AsmAnalyzer {
399cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
409cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    /**
419cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll     * Parses a JAR file and returns a list of all classes founds using a map
429cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll     * class name => ASM ClassReader. Class names are in the form "android.view.View".
439cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll     */
449cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    Map<String,ClassReader> parseInputJar(String inputJarPath) throws IOException {
459cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
469cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
479cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        ZipFile zip = new ZipFile(inputJarPath);
489cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        Enumeration<? extends ZipEntry> entries = zip.entries();
499cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        ZipEntry entry;
509cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        while (entries.hasMoreElements()) {
519cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            entry = entries.nextElement();
529cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            if (entry.getName().endsWith(".class")) {
539cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll                ClassReader cr = new ClassReader(zip.getInputStream(entry));
549cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll                String className = classReaderToAsmName(cr);
559cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll                classes.put(className, cr);
569cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            }
579cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        }
588252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael
599cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        return classes;
609cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    }
619cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
629cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    /**
639cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll     * Utility that returns the fully qualified ASM class name for a ClassReader.
649cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll     * E.g. it returns something like android/view/View.
659cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll     */
669cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    static String classReaderToAsmName(ClassReader classReader) {
679cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        if (classReader == null) {
689cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            return null;
699cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        } else {
709cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            return classReader.getClassName();
719cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        }
729cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    }
739cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
74adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll    /**
75adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll     * Filters the set of classes. Removes all classes that should not be included in the
76adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll     * filter or that should be excluded. This modifies the map in-place.
778252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael     *
78adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll     * @param classes The in-out map of classes to examine and filter. The map is filtered
79adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll     *                in-place.
80adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll     * @param filter  A filter describing which classes to include and which ones to exclude.
818252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael     * @param log
82adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll     */
838252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael    void filter(Map<String, ClassReader> classes, Filter filter, Logger log) {
849cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
859cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        Set<String> keys = classes.keySet();
869cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        for(Iterator<String> it = keys.iterator(); it.hasNext(); ) {
879cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            String key = it.next();
889cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll
89adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll            // TODO: We *could* filter out all private classes here: classes.get(key).getAccess().
908252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael
919cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            // remove if we don't keep it
92995b5ac934a7b584fecfa055d422fdba93aef812Raphael Moll            if (!filter.accept(key)) {
938252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael                log.debug("- Remove class " + key);
949cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll                it.remove();
959cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll            }
969cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll        }
979cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll    }
988252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael
999cdcde3017e17e1154341e697f855dd15d5d8a47Raphael Moll}
100