Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 1 | Android APK Checker |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 2 | |
| 3 | This compares the set of classes, fields, and methods used by an Android |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 4 | application against the published API. It identifies and reports the |
| 5 | use of any unpublished members or methods. |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 6 | |
| 7 | The public API description files live in the source tree, in |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 8 | frameworks/base/api/. The tip-of-tree version is in "current.xml", |
| 9 | and each officially released API has a numbered file (e.g. "6.xml"). |
| 10 | They're generated from the sources, and can take into acount javadoc |
| 11 | annotations like "@hide" in comments. |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 12 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 13 | The dependency set for an APK can be generated with "dexdeps". It finds |
| 14 | all classes, fields, and methods that are referenced by classes.dex but not |
| 15 | defined locally. The tool can't easily tell anything about a dependency |
| 16 | beyond the name (e.g. whether a class is a static or non-static inner |
| 17 | class), so while the output from dexdeps is similar in structure to the |
| 18 | API XML file, it has much less detail. |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 19 | |
| 20 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 21 | ==== Usage ==== |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 22 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 23 | % apkcheck [options] public-api.xml apk1.xml ... |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 24 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 25 | Provide the public API data file of choice, and one or more XML files |
| 26 | generated by dexdeps. The time required to parse and manipulate the |
| 27 | public API XML file is generally much larger than the time required to |
| 28 | analyze the APK, so if you have a large set of APKs it's best to run them |
| 29 | through in large batches. |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 30 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 31 | Options: |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 32 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 33 | --help |
| 34 | Show options summary. |
| 35 | |
Andy McFadden | a4707b1 | 2010-02-19 14:40:48 -0800 | [diff] [blame] | 36 | --uses-library=<lib.xml> |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 37 | Load additional public API list. This is intended for APKs that |
| 38 | use "uses-library" directives to pull in external libraries. Since |
| 39 | the external libraries are not part of the public API, their use |
| 40 | would otherwise be flagged as illegal by apkcheck. |
| 41 | |
Andy McFadden | a4707b1 | 2010-02-19 14:40:48 -0800 | [diff] [blame] | 42 | --ignore-package=<package-name> |
| 43 | Ignore errors generated by references to the named package (e.g. |
| 44 | "com.google.android.maps"). Warnings will be generated instead. |
| 45 | Useful for ignoring references to shared library content when |
| 46 | XML API data is not available. |
| 47 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 48 | --[no-]warn |
| 49 | Enable or disable warning messages. These are disabled by default. |
| 50 | |
| 51 | --[no-]error |
| 52 | Enable or disable error messages. These are enabled by default. If |
| 53 | you disable both warnings and errors you will only see a summary. |
| 54 | |
| 55 | In some cases involving generic signatures it may not be possible |
| 56 | to accurately reconstruct the public API. Some popular cases have |
| 57 | been hard-coded into the program. They can be included by specifying |
| 58 | "--uses-library=BUILTIN". |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 59 | |
| 60 | Example use: |
| 61 | |
| 62 | % dexdeps out/target/product/sapphire/system/app/Gmail.apk > Gmail.apk.xml |
| 63 | % apkcheck --uses-library=BUILTIN frameworks/base/api/current.xml Gmail.apk.xml |
| 64 | Gmail.apk.xml: summary: 0 errors, 15 warnings |
| 65 | |
| 66 | |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 67 | ==== Limitations ==== |
| 68 | |
| 69 | The API XML files have some ambiguous entries and are missing important |
| 70 | pieces. A summary of the issues follows. |
| 71 | |
| 72 | (1) Class names are not in binary form |
| 73 | |
| 74 | Example: |
| 75 | |
| 76 | type="android.os.Parcelable.Creator" |
| 77 | |
| 78 | This could be a Creator class in the package android.os.Parcelable, |
| 79 | or Parcelable.Creator in the package android.os. We can guess based on |
| 80 | capitalization, but that's unreliable. |
| 81 | |
| 82 | The API XML does specify each package in a <package> tag, so we should have |
| 83 | the full set of packages available. From this we can remove one element |
| 84 | at a time from the right until we match a known package. This will work |
| 85 | unless "android.os" and "android.os.Parcelable" are both valid packages. |
| 86 | |
| 87 | |
| 88 | (2) Public enums are not enumerated |
| 89 | |
| 90 | Enumeration classes are included, and always have two methods ("valueOf" |
| 91 | and "values"). What isn't included are entries for the fields representing |
| 92 | the enumeration values. This makes it look like an APK is referring |
| 93 | to non-public fields in the class. |
| 94 | |
Andy McFadden | 4fbfbb3 | 2010-02-19 16:15:27 -0800 | [diff] [blame] | 95 | If apkcheck sees a reference to an unknown field, and the field's defining |
| 96 | class appears to be an Enum (the superclass is java.lang.Enum), we emit |
| 97 | a warning instead of an error. |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 98 | |
| 99 | |
Andy McFadden | 4fbfbb3 | 2010-02-19 16:15:27 -0800 | [diff] [blame] | 100 | (3) Public annotation methods are not listed |
| 101 | |
| 102 | Annotation classes have trivial entries that show only the class name |
| 103 | and "implements java.lang.annotation.Annotation". It is not possible |
| 104 | to verify that a method call on an annotation is valid. |
| 105 | |
| 106 | If apkcheck sees a method call to an unknown method, and the class appears |
| 107 | to be an annotation (extends Object, implements Annotation, defines no |
| 108 | fields or methods), we emit a warning instead of an error. |
| 109 | |
| 110 | |
| 111 | (4) Covariant return types |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 112 | |
| 113 | Suppose a class defines a method "public Foo gimmeFoo()". Any subclass |
| 114 | that overrides that method must also return Foo, so it would seem that |
| 115 | there's no need to emit a method entry for gimmeFoo() in the subclasses. |
| 116 | |
| 117 | However, it's possible to override gimmeFoo with "public MegaFoo |
| 118 | gimmeFoo()" so long as MegaFoo is an instance of Foo. In that case it |
| 119 | is necessary to emit a new method entry, but the public API XML generator |
| 120 | does not. |
| 121 | |
| 122 | If apkcheck can't find an exact match for a method reference, but can |
| 123 | find a method that matches on everything but the return type, it will |
| 124 | emit a warning instead of an error. (We could be more thorough and try |
| 125 | to verify that the return types are related, but that's more trouble than |
| 126 | it's worth.) |
| 127 | |
| 128 | |
Andy McFadden | 4fbfbb3 | 2010-02-19 16:15:27 -0800 | [diff] [blame] | 129 | (5) Generic signatures |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 130 | |
| 131 | When generic signatures are used, the public API file will contain |
| 132 | entries like these: |
| 133 | |
| 134 | <parameter name="key" type="K"> |
| 135 | <parameter name="others" type="E..."> |
| 136 | <parameter name="map" type="java.util.Map<? extends K, ? extends V>"> |
| 137 | |
| 138 | The generic types are generally indistinguishable from classes in the |
| 139 | default package (i.e. that have no package name). In most cases they're |
| 140 | a single letter, so apkcheck includes a kluge that converts single-letter |
| 141 | class names to java.lang.Object. |
| 142 | |
| 143 | This often works, but falls apart in a few cases. For example: |
| 144 | |
| 145 | public <T extends Parcelable> T getParcelableExtra(String name) { |
| 146 | return mExtras == null ? null : mExtras.<T>getParcelable(name); |
| 147 | } |
| 148 | |
| 149 | This is emitted as: |
| 150 | |
| 151 | <method name="getParcelableExtra" return="T"> |
| 152 | |
| 153 | which gets converted to java.lang.Object. Unfortunately the APK wants |
| 154 | a method with a more specific return type (android.os.Parcelable), so |
| 155 | the lookup fails. |
| 156 | |
| 157 | There is no way to recover the actual type, because the generic signature |
| 158 | details are not present in the XML. This particular case will be handled |
| 159 | as a covariant return type. When the generic type is in the parameter |
| 160 | list, though, this isn't handled so easily. |
| 161 | |
| 162 | These cases are relatively few, so they were handled by baking the |
| 163 | signatures into the code (--uses-library=BUILTIN). (At some point it |
| 164 | may be worthwhile to try a little harder here.) |
| 165 | |
| 166 | |
Andy McFadden | 4fbfbb3 | 2010-02-19 16:15:27 -0800 | [diff] [blame] | 167 | (6) Use of opaque non-public types |
Andy McFadden | 0a62046 | 2010-02-19 12:53:31 -0800 | [diff] [blame] | 168 | |
| 169 | Some classes are not meant for public consumption, but are still referred |
| 170 | to by application code. For example, an opaque type might be passed to |
| 171 | the app as a cookie. |
| 172 | |
| 173 | Another example is the Dalvik annotation classes, like |
| 174 | dalvik.annotation.InnerClass. These are emitted by "dx", and referenced |
| 175 | from the DEX file, but not intended to be used by application code. |
| 176 | |
| 177 | If an APK refers to a non-public class, but doesn't access any fields |
| 178 | or methods, a warning is emitted instead of an error. |
Andy McFadden | 2eceaea | 2010-02-08 16:48:01 -0800 | [diff] [blame] | 179 | |