You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
6.8 KiB
180 lines
6.8 KiB
4 months ago
|
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.
|
||
|
|