Home | History | Annotate | only in /frameworks/base/tools/layoutlib/create
Up to higher level directory
NameDateSize
.classpath28-Mar-2012453
.project28-Mar-2012375
Android.mk28-Mar-2012857
manifest.txt28-Mar-201252
README.txt28-Mar-20129.4K
src/28-Mar-2012
tests/28-Mar-2012

README.txt

      1 # Copyright (C) 2008 The Android Open Source Project
      2 
      3 
      4 - Description -
      5 ---------------
      6 
      7 Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor
      8 to perform layout.
      9 
     10 
     11 - Usage -
     12 ---------
     13 
     14  ./layoutlib_create path/to/android.jar destination.jar
     15 
     16 
     17 - Design Overview -
     18 -------------------
     19 
     20 Layoutlib_create uses the "android.jar" containing all the Java code used by Android
     21 as generated by the Android build, right before the classes are converted to a DEX format.
     22 
     23 The Android JAR can't be used directly in Eclipse:
     24 - it contains references to native code (which we want to avoid in Eclipse),
     25 - some classes need to be overridden, for example all the drawing code that is
     26   replaced by Java 2D calls in Eclipse.
     27 - some of the classes that need to be changed are final and/or we need access
     28   to their private internal state.
     29 
     30 Consequently this tool:
     31 - parses the input JAR,
     32 - modifies some of the classes directly using some bytecode manipulation,
     33 - filters some packages and removes those we don't want in the output JAR,
     34 - injects some new classes,
     35 - generates a modified JAR file that is suitable for the Android plugin
     36   for Eclipse to perform rendering.
     37 
     38 The ASM library is used to do the bytecode modification using its visitor pattern API.
     39 
     40 The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the
     41 configuration is done in the main() method and the CreateInfo structure is expected to
     42 change with the Android platform as new classes are added, changed or removed.
     43 
     44 The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the
     45 platform, that provides all the necessary missing implementation for rendering graphics
     46 in Eclipse.
     47 
     48 
     49 
     50 - Implementation Notes -
     51 ------------------------
     52 
     53 The tool works in two phases:
     54 - first analyze the input jar (AsmAnalyzer class)
     55 - then generate the output jar (AsmGenerator class),
     56 
     57 
     58 - Analyzer
     59 ----------
     60 
     61 The goal of the analyzer is to create a graph of all the classes from the input JAR
     62 with their dependencies and then only keep the ones we want.
     63 
     64 To do that, the analyzer is created with a list of base classes to keep -- everything
     65 that derives from these is kept. Currently the one such class is android.view.View:
     66 since we want to render layouts, anything that is sort of a view needs to be kept.
     67 
     68 The analyzer is also given a list of class names to keep in the output.
     69 This is done using shell-like glob patterns that filter on the fully-qualified
     70 class names, for example "android.*.R**" ("*" does not matches dots whilst "**" does,
     71 and "." and "$" are interpreted as-is).
     72 In practice we almost but not quite request the inclusion of full packages.
     73 
     74 With this information, the analyzer parses the input zip to find all the classes.
     75 All classes deriving from the requested bases classes are kept.
     76 All classes which name matched the glob pattern are kept.
     77 The analysis then finds all the dependencies of the classes that are to be kept
     78 using an ASM visitor on the class, the field types, the method types and annotations types.
     79 Classes that belong to the current JRE are excluded.
     80 
     81 The output of the analyzer is a set of ASM ClassReader instances which are then
     82 fed to the generator.
     83 
     84 
     85 - Generator
     86 -----------
     87 
     88 The generator is constructed from a CreateInfo struct that acts as a config file
     89 and lists:
     90 - the classes to inject in the output JAR -- these classes are directly implemented
     91   in layoutlib_create and will be used to interface with the renderer in Eclipse.
     92 - specific methods to override (see method stubs details below).
     93 - specific methods for which to delegate calls.
     94 - specific methods to remove based on their return type.
     95 - specific classes to rename.
     96 
     97 Each of these are specific strategies we use to be able to modify the Android code
     98 to fit within the Eclipse renderer. These strategies are explained beow.
     99 
    100 The core method of the generator is transform(): it takes an input ASM ClassReader
    101 and modifies it to produce a byte array suitable for the final JAR file.
    102 
    103 The first step of the transformation is changing the name of the class in case
    104 we requested the class to be renamed. This uses the RenameClassAdapter to also rename
    105 all inner classes and references in methods and types. Note that other classes are
    106 not transformed and keep referencing the original name.
    107 
    108 The TransformClassAdapter is then used to process the potentially renamed class.
    109 All protected or private classes are market as public.
    110 All classes are made non-final.
    111 Interfaces are left as-is.
    112 
    113 If a method has a return type that must be erased, the whole method is skipped.
    114 Methods are also changed from protected/private to public.
    115 The code of the methods is then kept as-is, except for native methods which are
    116 replaced by a stub. Methods that are to be overridden are also replaced by a stub.
    117 
    118 The transformed class is then fed through the DelegateClassAdapter to implement
    119 method delegates. 
    120 
    121 Finally fields are also visited and changed from protected/private to public.
    122 
    123 
    124 - Method stubs
    125 --------------
    126 
    127 As indicated above, all native and overridden methods are replaced by a stub.
    128 We don't have the code to replace with in layoutlib_create.
    129 Instead the StubMethodAdapter replaces the code of the method by a call to
    130 OverrideMethod.invokeX(). When using the final JAR, the bridge can register
    131 listeners from these overridden method calls based on the method signatures.
    132 
    133 The listeners are currently pretty basic: we only pass the signature of the
    134 method being called, its caller object and a flag indicating whether the
    135 method was native. We do not currently provide the parameters. The listener
    136 can however specify the return value of the overridden method.
    137 
    138 This strategy is now obsolete and replaced by the method delegates.
    139 
    140 
    141 - Strategies
    142 ------------
    143 
    144 We currently have 4 strategies to deal with overriding the rendering code
    145 and make it run in Eclipse. Most of these strategies are implemented hand-in-hand
    146 by the bridge (which runs in Eclipse) and the generator.
    147 
    148 
    149 1- Class Injection
    150 
    151 This is the easiest: we currently inject 4 classes, namely:
    152 - OverrideMethod and its associated MethodListener and MethodAdapter are used
    153   to intercept calls to some specific methods that are stubbed out and change
    154   their return value.
    155 - CreateInfo class, which configured the generator. Not used yet, but could
    156   in theory help us track what the generator changed.
    157 
    158 
    159 2- Overriding methods
    160 
    161 As explained earlier, the creator doesn't have any replacement code for
    162 methods to override. Instead it removes the original code and replaces it
    163 by a call to a specific OveriddeMethod.invokeX(). The bridge then registers
    164 a listener on the method signature and can provide an implementation.
    165 
    166 This strategy is now obsolete and replaced by the method delegates.
    167 See strategy 5 below.
    168 
    169 
    170 3- Renaming classes
    171 
    172 This simply changes the name of a class in its definition, as well as all its
    173 references in internal inner classes and methods.
    174 Calls from other classes are not modified -- they keep referencing the original
    175 class name. This allows the bridge to literally replace an implementation.
    176 
    177 An example will make this easier: android.graphics.Paint is the main drawing
    178 class that we need to replace. To do so, the generator renames Paint to _original_Paint.
    179 Later the bridge provides its own replacement version of Paint which will be used
    180 by the rest of the Android stack. The replacement version of Paint can still use
    181 (either by inheritance or delegation) all the original non-native code of _original_Paint
    182 if it so desires.
    183 
    184 Some of the Android classes are basically wrappers over native objects and since
    185 we don't have the native code in Eclipse, we need to provide a full alternate
    186 implementation. Sub-classing doesn't work as some native methods are static and
    187 we don't control object creation.
    188 
    189 This won't rename/replace the inner static methods of a given class.
    190 
    191 
    192 4- Method erasure based on return type
    193 
    194 This is mostly an implementation detail of the bridge: in the Paint class
    195 mentioned above, some inner static classes are used to pass around
    196 attributes (e.g. FontMetrics, or the Style enum) and all the original implementation
    197 is native.
    198 
    199 In this case we have a strategy that tells the generator that anything returning, for
    200 example, the inner class Paint$Style in the Paint class should be discarded and the
    201 bridge will provide its own implementation.
    202 
    203 
    204 5- Method Delegates
    205 
    206 This strategy is used to override method implementations.
    207 Given a method SomeClass.MethodName(), 1 or 2 methods are generated:
    208 a- A copy of the original method named SomeClass.MethodName_Original().
    209    The content is the original method as-is from the reader.
    210    This step is omitted if the method is native, since it has no Java implementation.
    211 b- A brand new implementation of SomeClass.MethodName() which calls to a
    212    non-existing static method named SomeClass_Delegate.MethodName().
    213    The implementation of this 'delegate' method is done in layoutlib_brigde.
    214 
    215 The delegate method is a static method.
    216 If the original method is non-static, the delegate method receives the original 'this'
    217 as its first argument. If the original method is an inner non-static method, it also
    218 receives the inner 'this' as the second argument.
    219 
    220 
    221 
    222 - References -
    223 --------------
    224 
    225 
    226 The JVM Specification 2nd edition:
    227   http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
    228 
    229 Understanding bytecode:
    230   http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/
    231 
    232 Bytecode opcode list:
    233   http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
    234 
    235 ASM user guide:
    236   http://download.forge.objectweb.org/asm/asm-guide.pdf
    237 
    238 
    239 --
    240 end
    241