-APK Checker
+Android APK Checker
This compares the set of classes, fields, and methods used by an Android
-application against the published API.
+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 dependency set for an APK can be generated with
-"dexdeps".
+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.
-Use "apkcheck --help" to see a list of available options.
+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.
-Due to limitations and omissions in the API description files, there may
-be false-positives and false-negatives. When possible these are emitted
-as warnings rather than errors. (You may need to specify "--warn" to
-see them.)
+==== Usage ====
-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 adding the following
-to the command line:
+% apkcheck [options] public-api.xml apk1.xml ...
- --uses-library=BUILTIN
+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.
-The "--uses-library" option allows you to specify additional API source
-material. In the future this may be useful for applications that include
-libraries with the "uses-library" directive.
+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.
+
+ --[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:
Gmail.apk.xml: summary: 0 errors, 15 warnings
-By using the numbered API files (1.xml, 2.xml) instead of current.xml you
-can test the APK against a specific release.
+==== 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 superclass of
+the field's defining class is java.lang.Enum, we emit a warning instead
+of an error.
+
+
+(3) 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.)
+
+
+(4) 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.)
+
+
+(5) 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.