11160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta/* 21160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 31160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * 41160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 51160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * you may not use this file except in compliance with the License. 61160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * You may obtain a copy of the License at 71160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * 81160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 91160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * 101160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 111160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 121160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * See the License for the specific language governing permissions and 141160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta * limitations under the License. 151160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta */ 161160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 171160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Guptapackage com.android.tools.layoutlib.create; 181160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 191330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Guptaimport com.android.tools.layoutlib.java.LinkedHashMap_Delegate; 2017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport com.android.tools.layoutlib.java.System_Delegate; 2117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta 221160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Guptaimport org.objectweb.asm.ClassVisitor; 231160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Guptaimport org.objectweb.asm.MethodVisitor; 241160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Guptaimport org.objectweb.asm.Opcodes; 25b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Guptaimport org.objectweb.asm.Type; 261160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 275cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Guptaimport java.util.ArrayList; 28e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Guptaimport java.util.Arrays; 29e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Guptaimport java.util.HashSet; 301330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Guptaimport java.util.LinkedHashMap; 315cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Guptaimport java.util.List; 32b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Guptaimport java.util.Locale; 331330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Guptaimport java.util.Map; 34e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Guptaimport java.util.Set; 35e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta 361160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta/** 375cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta * Replaces calls to certain methods that do not exist in the Desktop VM. Useful for methods in the 385cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta * "java" package. 391160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta */ 401160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Guptapublic class ReplaceMethodCallsAdapter extends ClassVisitor { 41e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta 42e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta /** 43e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta * Descriptors for specialized versions {@link System#arraycopy} that are not present on the 44e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta * Desktop VM. 45e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta */ 4623e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<>(Arrays.asList( 47e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V", 48e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V")); 49e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta 5023e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta private static final List<MethodReplacer> METHOD_REPLACERS = new ArrayList<>(5); 515cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 52b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta private static final String ANDROID_LOCALE_CLASS = 53b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta "com/android/layoutlib/bridge/android/AndroidLocale"; 54b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 5517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta private static final String JAVA_LOCALE_CLASS = Type.getInternalName(java.util.Locale.class); 56b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta private static final Type STRING = Type.getType(String.class); 57b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 5817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta private static final String JAVA_LANG_SYSTEM = Type.getInternalName(System.class); 5917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta 605cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta // Static initialization block to initialize METHOD_REPLACERS. 615cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta static { 625cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta // Case 1: java.lang.System.arraycopy() 635cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 645cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta @Override 65f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 6617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta return JAVA_LANG_SYSTEM.equals(owner) && "arraycopy".equals(name) && 675cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta ARRAYCOPY_DESCRIPTORS.contains(desc); 685cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 695cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 705cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta @Override 7117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public void replace(MethodInformation mi) { 7217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V"; 735cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 745cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta }); 755cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 76b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta // Case 2: java.util.Locale.toLanguageTag() and java.util.Locale.getScript() 775cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 78b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 791330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta private final String LOCALE_TO_STRING = 801330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta Type.getMethodDescriptor(STRING, Type.getType(Locale.class)); 81b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 82b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta @Override 83f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 84b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta return JAVA_LOCALE_CLASS.equals(owner) && "()Ljava/lang/String;".equals(desc) && 85b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta ("toLanguageTag".equals(name) || "getScript".equals(name)); 86b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta } 87b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 88b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta @Override 8917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public void replace(MethodInformation mi) { 9017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.opcode = Opcodes.INVOKESTATIC; 9117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.owner = ANDROID_LOCALE_CLASS; 9217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.desc = LOCALE_TO_STRING; 93b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta } 94b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta }); 95b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 9682c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta // Case 3: java.util.Locale.adjustLanguageCode() or java.util.Locale.forLanguageTag() or 9782c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta // java.util.Locale.getDefault() 98b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 99b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 100b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta private final String STRING_TO_STRING = Type.getMethodDescriptor(STRING, STRING); 101b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta private final String STRING_TO_LOCALE = Type.getMethodDescriptor( 102b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta Type.getType(Locale.class), STRING); 10382c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta private final String VOID_TO_LOCALE = 10482c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta Type.getMethodDescriptor(Type.getType(Locale.class)); 105b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta 1065cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta @Override 107f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 108b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta return JAVA_LOCALE_CLASS.equals(owner) && 109b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta ("adjustLanguageCode".equals(name) && desc.equals(STRING_TO_STRING) || 11082c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta "forLanguageTag".equals(name) && desc.equals(STRING_TO_LOCALE) || 11182c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta "getDefault".equals(name) && desc.equals(VOID_TO_LOCALE)); 1125cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 1135cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 1145cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta @Override 11517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public void replace(MethodInformation mi) { 11617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.owner = ANDROID_LOCALE_CLASS; 11717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta } 11817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta }); 11917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta 12017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta // Case 4: java.lang.System.log?() 12117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 12217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta @Override 123f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 12417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta return JAVA_LANG_SYSTEM.equals(owner) && name.length() == 4 12517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta && name.startsWith("log"); 12617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta } 12717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta 12817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta @Override 12917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public void replace(MethodInformation mi) { 13017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta assert mi.desc.equals("(Ljava/lang/String;Ljava/lang/Throwable;)V") 13117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta || mi.desc.equals("(Ljava/lang/String;)V"); 13217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.name = "log"; 13317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta mi.owner = Type.getInternalName(System_Delegate.class); 1345cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 1355cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta }); 1361330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta 1377c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta // Case 5: java.lang.System time calls 1387c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 1397c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta @Override 1407c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 1417c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta return JAVA_LANG_SYSTEM.equals(owner) && name.equals("nanoTime"); 1427c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta } 1437c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta 1447c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta @Override 1457c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta public void replace(MethodInformation mi) { 1467c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta mi.name = "nanoTime"; 1477c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta mi.owner = Type.getInternalName(System_Delegate.class); 1487c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta } 1497c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta }); 1507c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 1517c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta @Override 1527c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 1537c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta return JAVA_LANG_SYSTEM.equals(owner) && name.equals("currentTimeMillis"); 1547c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta } 1557c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta 1567c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta @Override 1577c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta public void replace(MethodInformation mi) { 1587c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta mi.name = "currentTimeMillis"; 1597c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta mi.owner = Type.getInternalName(System_Delegate.class); 1607c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta } 1617c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta }); 1627c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta 1637c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta // Case 6: java.util.LinkedHashMap.eldest() 1641330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 1651330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta 1661330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta private final String VOID_TO_MAP_ENTRY = 1671330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta Type.getMethodDescriptor(Type.getType(Map.Entry.class)); 1681330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class); 1691330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta 1701330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta @Override 171f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 1721330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta return LINKED_HASH_MAP.equals(owner) && 1731330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta "eldest".equals(name) && 1741330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta VOID_TO_MAP_ENTRY.equals(desc); 1751330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta } 1761330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta 1771330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta @Override 1781330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta public void replace(MethodInformation mi) { 1791330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta mi.opcode = Opcodes.INVOKESTATIC; 1801330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class); 1811330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta mi.desc = Type.getMethodDescriptor( 1821330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class)); 1831330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta } 1841330f79f95fd14b53c393402fbcbf7b7bbdcbc60Deepanshu Gupta }); 185f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta 1867c4420bd04f8f56f6044f88e34616d8c5d96c7e9Deepanshu Gupta // Case 7: android.content.Context.getClassLoader() in LayoutInflater 187f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta METHOD_REPLACERS.add(new MethodReplacer() { 188f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // When LayoutInflater asks for a class loader, we must return the class loader that 189f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // cannot return app's custom views/classes. This is so that in case of any failure 190f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // or exception when instantiating the views, the IDE can replace it with a mock view 191f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // and have proper error handling. However, if a custom view asks for the class 192f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // loader, we must return a class loader that can find app's custom views as well. 193f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // Thus, we rewrite the call to get class loader in LayoutInflater to 194f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // getFrameworkClassLoader and inject a new method in Context. This leaves the normal 195f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta // method: Context.getClassLoader() free to be used by the apps. 196f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta private final String VOID_TO_CLASS_LOADER = 197f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta Type.getMethodDescriptor(Type.getType(ClassLoader.class)); 198f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta 199f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta @Override 200f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 201f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta return owner.equals("android/content/Context") && 202f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta sourceClass.equals("android/view/LayoutInflater") && 203f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta name.equals("getClassLoader") && 204f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta desc.equals(VOID_TO_CLASS_LOADER); 205f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta } 206f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta 207f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta @Override 208f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public void replace(MethodInformation mi) { 209f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta mi.name = "getFrameworkClassLoader"; 210f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta } 211f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta }); 2125cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 2135cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 214f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta /** 215f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta * If a method some.package.Class.Method(args) is called from some.other.Class, 216f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta * @param owner some/package/Class 217f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta * @param name Method 218f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta * @param desc (args)returnType 219f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta * @param sourceClass some/other/Class 220f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta * @return if the method invocation needs to be replaced by some other class. 221f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta */ 222f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public static boolean isReplacementNeeded(String owner, String name, String desc, 223f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta String sourceClass) { 2245cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta for (MethodReplacer replacer : METHOD_REPLACERS) { 225f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta if (replacer.isNeeded(owner, name, desc, sourceClass)) { 2265cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta return true; 2275cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 2285cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 2295cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta return false; 2305cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 2315cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 232f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta private final String mOriginalClassName; 233f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta 234f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta public ReplaceMethodCallsAdapter(ClassVisitor cv, String originalClassName) { 23523e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta super(Main.ASM_VERSION, cv); 236f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta mOriginalClassName = originalClassName; 2371160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta } 2381160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 2391160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta @Override 2401160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta public MethodVisitor visitMethod(int access, String name, String desc, String signature, 2411160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta String[] exceptions) { 2421160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta return new MyMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions)); 2431160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta } 2441160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 2451160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta private class MyMethodVisitor extends MethodVisitor { 2461160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 2471160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta public MyMethodVisitor(MethodVisitor mv) { 24823e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta super(Main.ASM_VERSION, mv); 2491160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta } 2501160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta 2511160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta @Override 25223e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta public void visitMethodInsn(int opcode, String owner, String name, String desc, 25323e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta boolean itf) { 2545cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta for (MethodReplacer replacer : METHOD_REPLACERS) { 255f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta if (replacer.isNeeded(owner, name, desc, mOriginalClassName)) { 25617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta MethodInformation mi = new MethodInformation(opcode, owner, name, desc); 25717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta replacer.replace(mi); 25817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta opcode = mi.opcode; 25917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta owner = mi.owner; 26017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta name = mi.name; 26117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta desc = mi.desc; 2625cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta break; 263e1960cc0b541cda93db94de5bef42dff922b9ec3Deepanshu Gupta } 2641160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta } 26523e47f5621271db9b84f53f15a3e3d81d8b8b48dDeepanshu Gupta super.visitMethodInsn(opcode, owner, name, desc, itf); 2661160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta } 2671160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta } 2685cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 26917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta private static class MethodInformation { 27017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public int opcode; 27117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public String owner; 27217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public String name; 27317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public String desc; 27417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta 27517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta public MethodInformation(int opcode, String owner, String name, String desc) { 27617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta this.opcode = opcode; 27717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta this.owner = owner; 27817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta this.name = name; 27917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta this.desc = desc; 28017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta } 28117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta } 28217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta 2835cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta private interface MethodReplacer { 284f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta boolean isNeeded(String owner, String name, String desc, String sourceClass); 2855cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta 2865cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta /** 28717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * Updates the MethodInformation with the new values of the method attributes - 288b80e42f93ff26984c410da0235dd10f463e5722aDeepanshu Gupta * opcode, owner, name and desc. 2895cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta */ 290f8ea750455eec81e4e6d877b3e18e29a86d4ec95Deepanshu Gupta void replace(MethodInformation mi); 2915cd9dde5a2a77c5095f985186d8f03147fd22870Deepanshu Gupta } 2921160e6d2f7018117b0c29a7e2adba9ece36faec1Deepanshu Gupta} 293