12eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden/* 22eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Copyright (C) 2010 The Android Open Source Project 32eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 42eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License"); 52eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * you may not use this file except in compliance with the License. 62eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * You may obtain a copy of the License at 72eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 82eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * http://www.apache.org/licenses/LICENSE-2.0 92eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Unless required by applicable law or agreed to in writing, software 112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS, 122eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * See the License for the specific language governing permissions and 142eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * limitations under the License. 152eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 162eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 172eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenpackage com.android.apkcheck; 182eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 192eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.ArrayList; 202eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.HashMap; 212eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.HashSet; 222eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.Iterator; 232eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.Set; 242eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 252eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden/** 262eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Container representing a class or interface with fields and methods. 272eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenpublic class ClassInfo { 292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private String mName; 302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden // methods are hashed on name:descriptor 312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private HashMap<String,MethodInfo> mMethodList; 322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden // fields are hashed on name:type 332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private HashMap<String,FieldInfo> mFieldList; 342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private String mSuperclassName; 362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden // is this a static inner class? 382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private String mIsStatic; 392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden // holds the name of the superclass and all declared interfaces 412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private ArrayList<String> mSuperNames; 422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 434fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden // is this an enumerated type? 444fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden private boolean mIsEnum; 454fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden // is this an annotation type? 464fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden private boolean mIsAnnotation; 474fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden 482eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private boolean mFlattening = false; 492eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private boolean mFlattened = false; 502eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 512eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 522eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Constructs a new ClassInfo with the provided class name. 532eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 542eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param className Binary class name without the package name, 552eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * e.g. "AlertDialog$Builder". 562eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param superclassName Fully-qualified binary or non-binary superclass 572eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * name (e.g. "java.lang.Enum"). 582eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param isStatic Class static attribute, may be "true", "false", or null. 592eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 602eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public ClassInfo(String className, String superclassName, String isStatic) { 612eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mName = className; 622eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mMethodList = new HashMap<String,MethodInfo>(); 632eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFieldList = new HashMap<String,FieldInfo>(); 642eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mSuperNames = new ArrayList<String>(); 652eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mIsStatic = isStatic; 662eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 672eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* 682eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Record the superclass name, and add it to the interface list 692eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * since we'll need to do the same "flattening" work on it. 702eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 712eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Interfaces and java.lang.Object have a null value. 722eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 732eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden if (superclassName != null) { 742eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mSuperclassName = superclassName; 752eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mSuperNames.add(superclassName); 762eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 772eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 782eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 792eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 802eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Returns the name of the class. 812eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 822eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public String getName() { 832eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mName; 842eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 852eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 862eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 872eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Returns the name of the superclass. 882eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 892eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public String getSuperclassName() { 902eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mSuperclassName; 912eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 922eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 932eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 942eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Returns the "static" attribute. 952eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 962eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * This is actually tri-state: 972eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * "true" means it is static 982eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * "false" means it's not static 992eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * null means it's unknown 1002eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 1012eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * The "unknown" state is associated with the APK input, while the 1022eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * known states are from the public API definition. 1032eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 1042eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * This relates to the handling of the "secret" first parameter to 1052eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * constructors of non-static inner classes. 1062eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1072eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public String getStatic() { 1082eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mIsStatic; 1092eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1124fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * Returns whether or not this class is an enumerated type. 1134fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden */ 1144fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden public boolean isEnum() { 1154fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden assert mFlattened; 1164fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden return mIsEnum; 1174fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden } 1184fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden 1194fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden /** 1204fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * Returns whether or not this class is an annotation type. 1214fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden */ 1224fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden public boolean isAnnotation() { 1234fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden assert mFlattened; 1244fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden return mIsAnnotation; 1254fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden } 1264fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden 1274fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden /** 1282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Adds a field to the list. 1292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public void addField(FieldInfo fieldInfo) { 1312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFieldList.put(fieldInfo.getNameAndType(), fieldInfo); 1322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Retrives a field from the list. 1362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 1372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param nameAndType fieldName:type 1382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public FieldInfo getField(String nameAndType) { 1402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mFieldList.get(nameAndType); 1412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1432eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1442eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Returns an iterator over all known fields. 1452eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1462eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public Iterator<FieldInfo> getFieldIterator() { 1472eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mFieldList.values().iterator(); 1482eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1492eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1502eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1512eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Adds a method to the list. 1522eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1532eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public void addMethod(MethodInfo methInfo) { 1542eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mMethodList.put(methInfo.getNameAndDescriptor(), methInfo); 1552eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1562eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1572eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1582eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Returns an iterator over all known methods. 1592eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1602eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public Iterator<MethodInfo> getMethodIterator() { 1612eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mMethodList.values().iterator(); 1622eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1632eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1642eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1652eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Retrieves a method from the list. 1662eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 1672eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param nameAndDescr methodName:descriptor 1682eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1692eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public MethodInfo getMethod(String nameAndDescr) { 1702eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mMethodList.get(nameAndDescr); 1712eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1722eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1732eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1742eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Retrieves a method from the list, matching on the part of the key 1752eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * before the return type. 1762eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 1772eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * The API file doesn't include an entry for a method that overrides 1782eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * a method in the superclass. Ordinarily this is a good thing, but 1792eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * if the override uses a covariant return type then the reference 1802eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * to it in the APK won't match. 1812eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 1822eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param nameAndDescr methodName:descriptor 1832eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 1842eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public MethodInfo getMethodIgnoringReturn(String nameAndDescr) { 1852eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String shortKey = nameAndDescr.substring(0, nameAndDescr.indexOf(')')+1); 1862eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1872eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden Iterator<MethodInfo> iter = getMethodIterator(); 1882eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden while (iter.hasNext()) { 1892eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden MethodInfo methInfo = iter.next(); 1902eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String nad = methInfo.getNameAndDescriptor(); 1912eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden if (nad.startsWith(shortKey)) 1922eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return methInfo; 1932eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1942eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1952eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return null; 1962eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 1972eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 1982eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 1992eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Returns true if the method and field lists are empty. 2002eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2012eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public boolean hasNoFieldMethod() { 2022eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return mMethodList.size() == 0 && mFieldList.size() == 0; 2032eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 2042eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2052eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 2062eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Adds an interface to the list of classes implemented by this class. 2072eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2082eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public void addInterface(String interfaceName) { 2092eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mSuperNames.add(interfaceName); 2102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 2112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2122eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 2132eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Flattens a class. This involves copying all methods and fields 2142eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * declared by the superclass and interfaces (and, recursively, their 2152eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * superclasses and interfaces) into the local structure. 2162eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 2172eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * The public API file must be fully parsed before calling here. 2184fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * 2194fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * This also detects if we're an Enum or Annotation. 2202eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2212eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden public void flattenClass(ApiList apiList) { 2222eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden if (mFlattened) 2232eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return; 2242eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2252eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* 2262eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Recursive class definitions aren't allowed in Java code, but 2272eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * there could be one in the API definition file. 2282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden if (mFlattening) { 2302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden throw new RuntimeException("Recursive invoke; current class is " 2312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden + mName); 2322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 2332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFlattening = true; 2342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* 2362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Normalize the ambiguous types. This requires regenerating the 2372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * field and method lists, because the signature is used as the 2382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * hash table key. 2392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden normalizeTypes(apiList); 2412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* 2434fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * Figure out if this class is an enumerated type. 2444fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden */ 2454fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden mIsEnum = "java.lang.Enum".equals(mSuperclassName); 2464fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden 2474fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden /* 2484fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * Figure out if this class is an annotation type. We expect it 2494fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * to extend Object, implement java.lang.annotation.Annotation, 2504fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * and declare no fields or methods. (If the API XML file is 2514fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * fixed, it will declare methods; but at that point having special 2524fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden * handling for annotations will be unnecessary.) 2534fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden */ 2544fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden if ("java.lang.Object".equals(mSuperclassName) && 2554fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden mSuperNames.contains("java.lang.annotation.Annotation") && 2564fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden hasNoFieldMethod()) 2574fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden { 2584fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden mIsAnnotation = true; 2594fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden } 2604fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden 2614fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden /* 2622eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Flatten our superclass and interfaces. 2632eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2642eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden for (int i = 0; i < mSuperNames.size(); i++) { 2652eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* 2662eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * The contents of mSuperNames are in an ambiguous form. 2672eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Normalize it to binary form before working with it. 2682eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2692eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String interfaceName = TypeUtils.ambiguousToBinaryName(mSuperNames.get(i), 2702eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden apiList); 2712eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden ClassInfo classInfo = lookupClass(interfaceName, apiList); 2722eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden if (classInfo == null) { 2732eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden ApkCheck.apkWarning("Class " + interfaceName + 2742eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden " not found (super of " + mName + ")"); 2752eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden continue; 2762eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 2772eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2782eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* flatten it */ 2792eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden classInfo.flattenClass(apiList); 2802eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2812eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /* copy everything from it in here */ 2822eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mergeFrom(classInfo); 2832eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 2842eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2852eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFlattened = true; 2862eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 2872eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 2882eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 2892eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Normalizes the type names used in field and method descriptors. 2902eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 2912eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * We call the field/method normalization function, which updates how 2922eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * it thinks of itself (and may be called multiple times from different 2932eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * classes). We then have to re-add it to the hash map because the 2942eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * key may have changed. (We're using an iterator, so we create a 2952eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * new hashmap and replace the old.) 2962eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 2972eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private void normalizeTypes(ApiList apiList) { 2982eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden Iterator<String> keyIter; 2992eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3002eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden HashMap<String,FieldInfo> tmpFieldList = new HashMap<String,FieldInfo>(); 3012eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden keyIter = mFieldList.keySet().iterator(); 3022eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden while (keyIter.hasNext()) { 3032eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String key = keyIter.next(); 3042eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden FieldInfo fieldInfo = mFieldList.get(key); 3052eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden fieldInfo.normalizeType(apiList); 3062eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden tmpFieldList.put(fieldInfo.getNameAndType(), fieldInfo); 3072eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 3082eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFieldList = tmpFieldList; 3092eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden HashMap<String,MethodInfo> tmpMethodList = new HashMap<String,MethodInfo>(); 3112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden keyIter = mMethodList.keySet().iterator(); 3122eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden while (keyIter.hasNext()) { 3132eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String key = keyIter.next(); 3142eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden MethodInfo methodInfo = mMethodList.get(key); 3152eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden methodInfo.normalizeTypes(apiList); 3162eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden tmpMethodList.put(methodInfo.getNameAndDescriptor(), methodInfo); 3172eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 3182eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mMethodList = tmpMethodList; 3192eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 3202eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3212eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 3222eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Merges the fields and methods from "otherClass" into this class. 3232eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 3242eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Redundant entries will be merged. We don't specify who the winner 3252eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * will be. 3262eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 3272eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private void mergeFrom(ClassInfo otherClass) { 3282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /*System.out.println("merging into " + getName() + ": fields=" + 3292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFieldList.size() + "/" + otherClass.mFieldList.size() + 3302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden ", methods=" + 3312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mMethodList.size() + "/" + otherClass.mMethodList.size());*/ 3322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mFieldList.putAll(otherClass.mFieldList); 3342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden mMethodList.putAll(otherClass.mMethodList); 3352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /*System.out.println(" now fields=" + mFieldList.size() + 3372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden ", methods=" + mMethodList.size());*/ 3382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 3392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden /** 3422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Finds the named class in the ApiList. 3432eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * 3442eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param className Fully-qualified dot notation (e.g. "java.lang.String") 3452eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @param apiList The hierarchy to search in. 3462eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * @return The class or null if not found. 3472eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */ 3482eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden private static ClassInfo lookupClass(String fullname, ApiList apiList) { 3492eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String packageName = TypeUtils.packageNameOnly(fullname); 3502eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden String className = TypeUtils.classNameOnly(fullname); 3512eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 3522eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden PackageInfo pkg = apiList.getPackage(packageName); 3532eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden if (pkg == null) 3542eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return null; 3552eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden return pkg.getClass(className); 3562eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden } 3572eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden} 3582eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden 359