OSDN Git Service

Updated README.
authorAndy McFadden <fadden@android.com>
Fri, 19 Feb 2010 20:53:31 +0000 (12:53 -0800)
committerAndy McFadden <fadden@android.com>
Fri, 19 Feb 2010 20:53:31 +0000 (12:53 -0800)
Document the trouble cases while I still remember what they are.

tools/apkcheck/README.txt

index 38e30d2..b922ee4 100644 (file)
@@ -1,31 +1,55 @@
-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:
 
@@ -34,6 +58,105 @@ 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&lt;? extends K, ? extends V&gt;">
+
+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.