-
Notifications
You must be signed in to change notification settings - Fork 28
package: core
We assume that you are fairly familiar with the Java reflection and some basic idea about Dalvik.
An Android application is packed into an APK file, which is actually a zip file. It contains images (res/
and resource.arsc
), linkable native libraries (lib/*.so
), code (classes.dex
), the manifest file (AndroidManifest.xml
), signatures (META-INF/
) and some other files.
Logically, the code part is composed of classes, each with a list of methods and fields. The core
package provides abstractions for Android classes, methods, fields and primitive Java type values, designed with efficiency in mind. It works very much alike Java reflection. PATDroid's core package is designed to provide a superset of Java reflection, while being neutral to the underlying bytecodes.
Here are the list of classes and their short description in the core
package:
-
patdroid.core.ClassInfo
denotes a Java class, uniquely identified by its fully qualified class name, e.g. "java.lang.String". -
patdroid.core.ClassDetail
denotes the details about a Java class, including its methods, fields, superclass, etc. The point of separatingClassDetail
fromClassInfo
is to allow the on-demand loading of the details of a class. See below for details. -
patdroid.core.ClassDetailLoader
the base class for loadingClassDetail
s -
patdroid.core.ReflectionClassDetailLoader
a ClassDetailLoader that loads classes through standard Java reflection -
patdroid.core.MethodInfo
denotes a method, consisting of its name, the qualifier (private, public, static, etc), parameter types (ClassInfo
s), return type and the class that contains this method. -
patdroid.core.FieldInfo
denotes a field within a class, with name, qualifier and type. -
patdroid.core.PrimitiveInfo
is a unified abstraction of Java primitive types (int, char, long, double), basically everything that are not an Object.
Next we explain how these abstractions are related to each other.
ClassInfo
is the abstraction for a Java class. ClassInfo
s are forbidden to be constructed. To obtain the ClassInfo
for a given class, use the find
-series functions. For example, ClassInfo.findOrCreateClass("java.lang.String")
returns the representation for the built-in String class.
With a ClassInfo
, one can query many things. The javadoc for each API is self-explainable. Note that the difference between the findMethodHere()
and the findMethod()
is that the former only queries the methods declared within the class in question while the later one also checks parent class(es).
This is a classic problem. Suppose we have two classes Foo and Bar. Foo has a method that takes a Bar parameter and Bar has a method that takes a Foo. If we load Foo, we in terms need to load Bar. But loading Bar then falls back to loading Foo, which forms a circular situation. To solve this, we separate the details about a class (what methods and fields it contains) to ClassDetail
. When loading Foo, we just create a ClassInfo
for Bar with no details. Then Foo is loaded and we got a ClassInfo
for Foo as well as its ClassDetail
. Next we load Bar to obtain its ClassDetail
. One should avoid using ClassDetail
directly and instead access everything from a ClassInfo
, because it ensures that if the detail is not found, the correct loading procedure will be started.
One can design different loaders to load ClassDetails from different sources. For example, we can have one loader loading from an APK file, another loading from Android SDK, and a third one loading from the standard library jar. ClassInfo
has a rootDetailLoader
which specifies the first loader we should try when we want to load a ClassDetail
. If this loader cannot load the detail, then it should fall back to the second loader and so on so forth. The last one in the chain, which should always be the ClassDetailLoader
base class, simply throws an exception saying the detail cannot be found.
There is nothing particular about MethodInfo
, simply a collection of everything you saw from a function prototype. One special thing is that everything MethodInfo
s stored within a ClassInfo
should have its myClass
pointed back to the ClassInfo
. However, if you want to construct an arbitrary function prototype, use MethodInfo.makePrototype
. A MethodInfo
has the support for computing the hash of the function signature to make it easier to check if two methods have the same prototype. For details, refer to a JVM internal book. Some demos about the APIs:
ClassInfo c = ClassInfo.findClass("java.lang.String");
// String concat(String other);
MethodInfo mprot = MethodInfo.makePrototype("concat", c, new ClassInfo[] {c}, 0);
MethodInfo m = c.findMethodHere(mprot);
// m.hasSameSignature(mprot) == true
c.findMethodsHere("indexOf") // return two versions
// int indexOf(String str)
// int indexOf(String str, int fromIndex)
c.findMethodHere("valueOf", c, new ClassInfo[] {ClassInfo.primitiveDouble}, Modifier.STATIC);
// finds: static String valueOf(double d)
Again, this thing has nothing special.
We make this abstraction to unify the representation for the values for Java primitive types. It is type-safe and cast-safe. The below code snippet should be self-explainable:
PrimitiveInfo aLong = new PrimitiveInfo(120l);
PrimitiveInfo aFloat = new PrimitiveInfo(2.4f);
aLong.intValue(); // ASSERT FAILURE: it is a long
aFloat.floatValue(); // == 2.4f
PrimitiveInfo theDouble = aFloat.castTo(ClassInfo.primitiveDouble); // safe cast
theDouble.doubleValue(); // == 2.4
theDouble.floatValue(); // ASSERT FAILURE: it is a double not a float