1a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll/* 2a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * Copyright (C) 2009 The Android Open Source Project 3a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * 4a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * Licensed under the Apache License, Version 2.0 (the "License"); 5a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * you may not use this file except in compliance with the License. 6a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * You may obtain a copy of the License at 7a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * 8a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * http://www.apache.org/licenses/LICENSE-2.0 9a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * 10a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * Unless required by applicable law or agreed to in writing, software 11a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * distributed under the License is distributed on an "AS IS" BASIS, 12a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * See the License for the specific language governing permissions and 14a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * limitations under the License. 15a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll */ 16a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 17a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollpackage com.android.mkstubs; 18a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 198252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphaelimport com.android.mkstubs.Main.Logger; 20a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport com.android.mkstubs.stubber.ClassStubber; 21a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 22a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport org.objectweb.asm.ClassReader; 23a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport org.objectweb.asm.ClassVisitor; 24a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport org.objectweb.asm.ClassWriter; 25a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 26a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.io.File; 27a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.io.FileOutputStream; 28a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.io.IOException; 29a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.util.Map; 30a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.util.Map.Entry; 318252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphaelimport java.util.TreeMap; 32a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.util.jar.JarEntry; 33a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollimport java.util.jar.JarOutputStream; 34a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 35a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll/** 36adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * Given a set of already filtered classes, this filters out all private members, 37adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * stubs the remaining classes and then generates a Jar out of them. 38adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * <p/> 39adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * This is an helper extracted for convenience. Callers just need to use 40adf4543e57086070c95b3ef439dbb6679b0bd562Raphael Moll * {@link #generateStubbedJar(File, Map, Filter)}. 41a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll */ 42a4335fbe026cff184eea04b406343296870ccb2eRaphael Mollclass StubGenerator { 43a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 448252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael private Logger mLog; 458252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael 468252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael public StubGenerator(Logger log) { 478252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael mLog = log; 488252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael } 498252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael 50a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll /** 51a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * Generate source for the stubbed classes, mostly for debug purposes. 528252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael * @throws IOException 53a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll */ 54a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll public void generateStubbedJar(File destJar, 55a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll Map<String, ClassReader> classes, 56995b5ac934a7b584fecfa055d422fdba93aef812Raphael Moll Filter filter) throws IOException { 57a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 58a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll TreeMap<String, byte[]> all = new TreeMap<String, byte[]>(); 59a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 60a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll for (Entry<String, ClassReader> entry : classes.entrySet()) { 61a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll ClassReader cr = entry.getValue(); 628252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael 63995b5ac934a7b584fecfa055d422fdba93aef812Raphael Moll byte[] b = visitClassStubber(cr, filter); 64a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll String name = classNameToEntryPath(cr.getClassName()); 65a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll all.put(name, b); 66a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll } 67a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 68a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll createJar(new FileOutputStream(destJar), all); 69a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 708252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael mLog.debug("Wrote %s", destJar.getPath()); 71a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll } 72a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 73a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll /** 74a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * Utility method that converts a fully qualified java name into a JAR entry path 75a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * e.g. for the input "android.view.View" it returns "android/view/View.class" 76a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll */ 77a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll String classNameToEntryPath(String className) { 78a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll return className.replaceAll("\\.", "/").concat(".class"); 79a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll } 80a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 81a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll /** 82a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * Writes the JAR file. 838252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael * 848252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael * @param outStream The file output stream were to write the JAR. 85a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * @param all The map of all classes to output. 86a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll * @throws IOException if an I/O error has occurred 87a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll */ 88a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll void createJar(FileOutputStream outStream, Map<String,byte[]> all) throws IOException { 89a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll JarOutputStream jar = new JarOutputStream(outStream); 90a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll for (Entry<String, byte[]> entry : all.entrySet()) { 91a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll String name = entry.getKey(); 92a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll JarEntry jar_entry = new JarEntry(name); 93a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll jar.putNextEntry(jar_entry); 94a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll jar.write(entry.getValue()); 95a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll jar.closeEntry(); 96a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll } 97a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll jar.flush(); 98a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll jar.close(); 99a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll } 1008252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael 101995b5ac934a7b584fecfa055d422fdba93aef812Raphael Moll byte[] visitClassStubber(ClassReader cr, Filter filter) { 1028252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael mLog.debug("Stub " + cr.getClassName()); 103a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 104a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll // Rewrite the new class from scratch, without reusing the constant pool from the 105a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll // original class reader. 106a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 107a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll 108a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll ClassVisitor stubWriter = new ClassStubber(cw); 1098252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter, mLog); 110995b5ac934a7b584fecfa055d422fdba93aef812Raphael Moll cr.accept(classFilter, 0 /*flags*/); 111a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll return cw.toByteArray(); 112a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll } 113a4335fbe026cff184eea04b406343296870ccb2eRaphael Moll} 114