| Android APK Checker |
| |
| This compares the set of classes, fields, and methods used by an Android |
| application against the published API. It identifies and reports the |
| use of any unpublished members or methods. |
| |
| The public API description files live in the source tree, in |
| frameworks/base/api/. The tip-of-tree version is in "current.xml", |
| and each officially released API has a numbered file (e.g. "6.xml"). |
| They're generated from the sources, and can take into acount javadoc |
| annotations like "@hide" in comments. |
| |
| The dependency set for an APK can be generated with "dexdeps". It finds |
| all classes, fields, and methods that are referenced by classes.dex but not |
| defined locally. The tool can't easily tell anything about a dependency |
| beyond the name (e.g. whether a class is a static or non-static inner |
| class), so while the output from dexdeps is similar in structure to the |
| API XML file, it has much less detail. |
| |
| |
| ==== Usage ==== |
| |
| % apkcheck [options] public-api.xml apk1.xml ... |
| |
| Provide the public API data file of choice, and one or more XML files |
| generated by dexdeps. The time required to parse and manipulate the |
| public API XML file is generally much larger than the time required to |
| analyze the APK, so if you have a large set of APKs it's best to run them |
| through in large batches. |
| |
| Options: |
| |
| --help |
| Show options summary. |
| |
| --uses-library=<lib.xml> |
| Load additional public API list. This is intended for APKs that |
| use "uses-library" directives to pull in external libraries. Since |
| the external libraries are not part of the public API, their use |
| would otherwise be flagged as illegal by apkcheck. |
| |
| --ignore-package=<package-name> |
| Ignore errors generated by references to the named package (e.g. |
| "com.google.android.maps"). Warnings will be generated instead. |
| Useful for ignoring references to shared library content when |
| XML API data is not available. |
| |
| --[no-]warn |
| Enable or disable warning messages. These are disabled by default. |
| |
| --[no-]error |
| Enable or disable error messages. These are enabled by default. If |
| you disable both warnings and errors you will only see a summary. |
| |
| In some cases involving generic signatures it may not be possible |
| to accurately reconstruct the public API. Some popular cases have |
| been hard-coded into the program. They can be included by specifying |
| "--uses-library=BUILTIN". |
| |
| Example use: |
| |
| % dexdeps out/target/product/sapphire/system/app/Gmail.apk > Gmail.apk.xml |
| % apkcheck --uses-library=BUILTIN frameworks/base/api/current.xml Gmail.apk.xml |
| Gmail.apk.xml: summary: 0 errors, 15 warnings |
| |
| |
| ==== Limitations ==== |
| |
| The API XML files have some ambiguous entries and are missing important |
| pieces. A summary of the issues follows. |
| |
| (1) Class names are not in binary form |
| |
| Example: |
| |
| type="android.os.Parcelable.Creator" |
| |
| This could be a Creator class in the package android.os.Parcelable, |
| or Parcelable.Creator in the package android.os. We can guess based on |
| capitalization, but that's unreliable. |
| |
| The API XML does specify each package in a <package> tag, so we should have |
| the full set of packages available. From this we can remove one element |
| at a time from the right until we match a known package. This will work |
| unless "android.os" and "android.os.Parcelable" are both valid packages. |
| |
| |
| (2) Public enums are not enumerated |
| |
| Enumeration classes are included, and always have two methods ("valueOf" |
| and "values"). What isn't included are entries for the fields representing |
| the enumeration values. This makes it look like an APK is referring |
| to non-public fields in the class. |
| |
| If apkcheck sees a reference to an unknown field, and the field's defining |
| class appears to be an Enum (the superclass is java.lang.Enum), we emit |
| a warning instead of an error. |
| |
| |
| (3) Public annotation methods are not listed |
| |
| Annotation classes have trivial entries that show only the class name |
| and "implements java.lang.annotation.Annotation". It is not possible |
| to verify that a method call on an annotation is valid. |
| |
| If apkcheck sees a method call to an unknown method, and the class appears |
| to be an annotation (extends Object, implements Annotation, defines no |
| fields or methods), we emit a warning instead of an error. |
| |
| |
| (4) Covariant return types |
| |
| Suppose a class defines a method "public Foo gimmeFoo()". Any subclass |
| that overrides that method must also return Foo, so it would seem that |
| there's no need to emit a method entry for gimmeFoo() in the subclasses. |
| |
| However, it's possible to override gimmeFoo with "public MegaFoo |
| gimmeFoo()" so long as MegaFoo is an instance of Foo. In that case it |
| is necessary to emit a new method entry, but the public API XML generator |
| does not. |
| |
| If apkcheck can't find an exact match for a method reference, but can |
| find a method that matches on everything but the return type, it will |
| emit a warning instead of an error. (We could be more thorough and try |
| to verify that the return types are related, but that's more trouble than |
| it's worth.) |
| |
| |
| (5) Generic signatures |
| |
| When generic signatures are used, the public API file will contain |
| entries like these: |
| |
| <parameter name="key" type="K"> |
| <parameter name="others" type="E..."> |
| <parameter name="map" type="java.util.Map<? extends K, ? extends V>"> |
| |
| The generic types are generally indistinguishable from classes in the |
| default package (i.e. that have no package name). In most cases they're |
| a single letter, so apkcheck includes a kluge that converts single-letter |
| class names to java.lang.Object. |
| |
| This often works, but falls apart in a few cases. For example: |
| |
| public <T extends Parcelable> T getParcelableExtra(String name) { |
| return mExtras == null ? null : mExtras.<T>getParcelable(name); |
| } |
| |
| This is emitted as: |
| |
| <method name="getParcelableExtra" return="T"> |
| |
| which gets converted to java.lang.Object. Unfortunately the APK wants |
| a method with a more specific return type (android.os.Parcelable), so |
| the lookup fails. |
| |
| There is no way to recover the actual type, because the generic signature |
| details are not present in the XML. This particular case will be handled |
| as a covariant return type. When the generic type is in the parameter |
| list, though, this isn't handled so easily. |
| |
| These cases are relatively few, so they were handled by baking the |
| signatures into the code (--uses-library=BUILTIN). (At some point it |
| may be worthwhile to try a little harder here.) |
| |
| |
| (6) Use of opaque non-public types |
| |
| Some classes are not meant for public consumption, but are still referred |
| to by application code. For example, an opaque type might be passed to |
| the app as a cookie. |
| |
| Another example is the Dalvik annotation classes, like |
| dalvik.annotation.InnerClass. These are emitted by "dx", and referenced |
| from the DEX file, but not intended to be used by application code. |
| |
| If an APK refers to a non-public class, but doesn't access any fields |
| or methods, a warning is emitted instead of an error. |
| |