14b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/* 24b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project 34b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * 44b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License"); 54b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * you may not use this file except in compliance with the License. 64b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * You may obtain a copy of the License at 74b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * 84b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * http://www.apache.org/licenses/LICENSE-2.0 94b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * 104b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software 114b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS, 124b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * See the License for the specific language governing permissions and 144b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * limitations under the License. 154b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */ 164b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 174b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetpackage com.android.tools.layoutlib.create; 184b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 194b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.objectweb.asm.ClassVisitor; 204b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.objectweb.asm.MethodVisitor; 214b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.objectweb.asm.Opcodes; 224b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 234b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport java.util.Set; 244b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 254b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/** 264b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * A {@link DelegateClassAdapter} can transform some methods from a class into 274b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * delegates that defer the call to an associated delegate class. 284b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * <p/> 294b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * This is used to override specific methods and or all native methods in classes. 304b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */ 31f7270ba9083e5b0069f73fc88aec439ab439275bTor Norbyepublic class DelegateClassAdapter extends ClassVisitor { 324b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 33865c3bef54228a353fd449a093b0c8d155618296Raphael Moll /** Suffix added to original methods. */ 34865c3bef54228a353fd449a093b0c8d155618296Raphael Moll private static final String ORIGINAL_SUFFIX = "_Original"; 35865c3bef54228a353fd449a093b0c8d155618296Raphael Moll private static String CONSTRUCTOR = "<init>"; 36865c3bef54228a353fd449a093b0c8d155618296Raphael Moll private static String CLASS_INIT = "<clinit>"; 37865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 384b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet public final static String ALL_NATIVES = "<<all_natives>>"; 394b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 404b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet private final String mClassName; 414b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet private final Set<String> mDelegateMethods; 424b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet private final Log mLog; 434b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 444b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet /** 454b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Creates a new {@link DelegateClassAdapter} that can transform some methods 464b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * from a class into delegates that defer the call to an associated delegate class. 474b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * <p/> 484b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * This is used to override specific methods and or all native methods in classes. 494b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * 504b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * @param log The logger object. Must not be null. 514b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * @param cv the class visitor to which this adapter must delegate calls. 524b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * @param className The internal class name of the class to visit, 534b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * e.g. <code>com/android/SomeClass$InnerClass</code>. 544b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * @param delegateMethods The set of method names to modify and/or the 554b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * special constant {@link #ALL_NATIVES} to convert all native methods. 564b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */ 574b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet public DelegateClassAdapter(Log log, 584b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet ClassVisitor cv, 594b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet String className, 604b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet Set<String> delegateMethods) { 61f7270ba9083e5b0069f73fc88aec439ab439275bTor Norbye super(Opcodes.ASM4, cv); 624b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet mLog = log; 634b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet mClassName = className; 644b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet mDelegateMethods = delegateMethods; 654b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet } 664b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 674b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet //---------------------------------- 684b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet // Methods from the ClassAdapter 694b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 704b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet @Override 714b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet public MethodVisitor visitMethod(int access, String name, String desc, 724b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet String signature, String[] exceptions) { 734b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 744b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 754b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet boolean isNative = (access & Opcodes.ACC_NATIVE) != 0; 764b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 774b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) || 784b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet mDelegateMethods.contains(name); 794b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 80865c3bef54228a353fd449a093b0c8d155618296Raphael Moll if (!useDelegate) { 81865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // Not creating a delegate for this method, pass it as-is from the reader 82865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // to the writer. 83865c3bef54228a353fd449a093b0c8d155618296Raphael Moll return super.visitMethod(access, name, desc, signature, exceptions); 844b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet } 854b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet 864b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet if (useDelegate) { 87865c3bef54228a353fd449a093b0c8d155618296Raphael Moll if (CONSTRUCTOR.equals(name) || CLASS_INIT.equals(name)) { 88865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // We don't currently support generating delegates for constructors. 89865c3bef54228a353fd449a093b0c8d155618296Raphael Moll throw new UnsupportedOperationException( 90865c3bef54228a353fd449a093b0c8d155618296Raphael Moll String.format( 91865c3bef54228a353fd449a093b0c8d155618296Raphael Moll "Delegate doesn't support overriding constructor %1$s:%2$s(%3$s)", //$NON-NLS-1$ 92865c3bef54228a353fd449a093b0c8d155618296Raphael Moll mClassName, name, desc)); 934b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet } 944b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet } 95865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 96865c3bef54228a353fd449a093b0c8d155618296Raphael Moll if (isNative) { 97865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // Remove native flag 98865c3bef54228a353fd449a093b0c8d155618296Raphael Moll access = access & ~Opcodes.ACC_NATIVE; 99865c3bef54228a353fd449a093b0c8d155618296Raphael Moll MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions); 100865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 101865c3bef54228a353fd449a093b0c8d155618296Raphael Moll DelegateMethodAdapter2 a = new DelegateMethodAdapter2( 102865c3bef54228a353fd449a093b0c8d155618296Raphael Moll mLog, null /*mwOriginal*/, mwDelegate, mClassName, name, desc, isStatic); 103865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 104865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // A native has no code to visit, so we need to generate it directly. 105865c3bef54228a353fd449a093b0c8d155618296Raphael Moll a.generateDelegateCode(); 106865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 107865c3bef54228a353fd449a093b0c8d155618296Raphael Moll return mwDelegate; 108865c3bef54228a353fd449a093b0c8d155618296Raphael Moll } 109865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 110865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // Given a non-native SomeClass.MethodName(), we want to generate 2 methods: 111865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // - A copy of the original method named SomeClass.MethodName_Original(). 112865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // The content is the original method as-is from the reader. 113865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // - A brand new implementation of SomeClass.MethodName() which calls to a 114865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // non-existing method named SomeClass_Delegate.MethodName(). 115865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // The implementation of this 'delegate' method is done in layoutlib_brigde. 116865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 117865c3bef54228a353fd449a093b0c8d155618296Raphael Moll int accessDelegate = access; 118865c3bef54228a353fd449a093b0c8d155618296Raphael Moll // change access to public for the original one 119caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll if (Main.sOptions.generatePublicAccess) { 120caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE); 121caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll access |= Opcodes.ACC_PUBLIC; 122caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll } 123865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 124865c3bef54228a353fd449a093b0c8d155618296Raphael Moll MethodVisitor mwOriginal = super.visitMethod(access, name + ORIGINAL_SUFFIX, 125865c3bef54228a353fd449a093b0c8d155618296Raphael Moll desc, signature, exceptions); 126865c3bef54228a353fd449a093b0c8d155618296Raphael Moll MethodVisitor mwDelegate = super.visitMethod(accessDelegate, name, 127865c3bef54228a353fd449a093b0c8d155618296Raphael Moll desc, signature, exceptions); 128865c3bef54228a353fd449a093b0c8d155618296Raphael Moll 129865c3bef54228a353fd449a093b0c8d155618296Raphael Moll DelegateMethodAdapter2 a = new DelegateMethodAdapter2( 130865c3bef54228a353fd449a093b0c8d155618296Raphael Moll mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic); 131865c3bef54228a353fd449a093b0c8d155618296Raphael Moll return a; 1324b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet } 1334b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet} 134