blob: 894611b3e728b4a80e925d878758c7ec3f73d4bf [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001# Copyright (C) 2008 The Android Open Source Project
2
3
4- Description -
5---------------
6
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -08007Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008to perform layout.
9
10
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011- Usage -
12---------
13
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080014 ./layoutlib_create path/to/android.jar destination.jar
15
16
17- Design Overview -
18-------------------
19
20Layoutlib_create uses the "android.jar" containing all the Java code used by Android
21as generated by the Android build, right before the classes are converted to a DEX format.
22
23The 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
30Consequently this tool:
31- parses the input JAR,
32- modifies some of the classes directly using some bytecode manipulation,
Raphael Moll865c3be2011-06-17 17:12:52 -070033- filters some packages and removes those we don't want in the output JAR,
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080034- injects some new classes,
Raphael Moll865c3be2011-06-17 17:12:52 -070035- generates a modified JAR file that is suitable for the Android plugin
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080036 for Eclipse to perform rendering.
37
38The ASM library is used to do the bytecode modification using its visitor pattern API.
39
40The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the
41configuration is done in the main() method and the CreateInfo structure is expected to
42change with the Android platform as new classes are added, changed or removed.
43
44The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the
45platform, that provides all the necessary missing implementation for rendering graphics
46in Eclipse.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
48
49
50- Implementation Notes -
51------------------------
52
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080053The tool works in two phases:
54- first analyze the input jar (AsmAnalyzer class)
55- then generate the output jar (AsmGenerator class),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
57
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080058- Analyzer
59----------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080061The goal of the analyzer is to create a graph of all the classes from the input JAR
62with their dependencies and then only keep the ones we want.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080064To do that, the analyzer is created with a list of base classes to keep -- everything
65that derives from these is kept. Currently the one such class is android.view.View:
Raphael Moll865c3be2011-06-17 17:12:52 -070066since we want to render layouts, anything that is sort of a view needs to be kept.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080068The analyzer is also given a list of class names to keep in the output.
69This is done using shell-like glob patterns that filter on the fully-qualified
70class names, for example "android.*.R**" ("*" does not matches dots whilst "**" does,
71and "." and "$" are interpreted as-is).
72In practice we almost but not quite request the inclusion of full packages.
73
74With this information, the analyzer parses the input zip to find all the classes.
75All classes deriving from the requested bases classes are kept.
76All classes which name matched the glob pattern are kept.
77The analysis then finds all the dependencies of the classes that are to be kept
78using an ASM visitor on the class, the field types, the method types and annotations types.
79Classes that belong to the current JRE are excluded.
80
81The output of the analyzer is a set of ASM ClassReader instances which are then
82fed to the generator.
83
84
85- Generator
86-----------
87
88The generator is constructed from a CreateInfo struct that acts as a config file
89and 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).
Raphael Moll865c3be2011-06-17 17:12:52 -070093- specific methods for which to delegate calls.
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -080094- specific methods to remove based on their return type.
95- specific classes to rename.
96
97Each of these are specific strategies we use to be able to modify the Android code
98to fit within the Eclipse renderer. These strategies are explained beow.
99
100The core method of the generator is transform(): it takes an input ASM ClassReader
101and modifies it to produce a byte array suitable for the final JAR file.
102
103The first step of the transformation is changing the name of the class in case
104we requested the class to be renamed. This uses the RenameClassAdapter to also rename
105all inner classes and references in methods and types. Note that other classes are
106not transformed and keep referencing the original name.
107
108The TransformClassAdapter is then used to process the potentially renamed class.
109All protected or private classes are market as public.
110All classes are made non-final.
111Interfaces are left as-is.
112
113If a method has a return type that must be erased, the whole method is skipped.
114Methods are also changed from protected/private to public.
115The code of the methods is then kept as-is, except for native methods which are
116replaced by a stub. Methods that are to be overridden are also replaced by a stub.
117
Raphael Moll865c3be2011-06-17 17:12:52 -0700118The transformed class is then fed through the DelegateClassAdapter to implement
119method delegates.
120
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -0800121Finally fields are also visited and changed from protected/private to public.
122
123
124- Method stubs
125--------------
126
127As indicated above, all native and overridden methods are replaced by a stub.
128We don't have the code to replace with in layoutlib_create.
129Instead the StubMethodAdapter replaces the code of the method by a call to
130OverrideMethod.invokeX(). When using the final JAR, the bridge can register
131listeners from these overridden method calls based on the method signatures.
132
133The listeners are currently pretty basic: we only pass the signature of the
134method being called, its caller object and a flag indicating whether the
135method was native. We do not currently provide the parameters. The listener
136can however specify the return value of the overridden method.
137
Raphael Moll865c3be2011-06-17 17:12:52 -0700138This strategy is now obsolete and replaced by the method delegates.
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -0800139
140
141- Strategies
142------------
143
144We currently have 4 strategies to deal with overriding the rendering code
145and make it run in Eclipse. Most of these strategies are implemented hand-in-hand
146by the bridge (which runs in Eclipse) and the generator.
147
148
1491- Class Injection
150
151This 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
1592- Overriding methods
160
161As explained earlier, the creator doesn't have any replacement code for
162methods to override. Instead it removes the original code and replaces it
163by a call to a specific OveriddeMethod.invokeX(). The bridge then registers
164a listener on the method signature and can provide an implementation.
165
Raphael Moll865c3be2011-06-17 17:12:52 -0700166This strategy is now obsolete and replaced by the method delegates.
167See strategy 5 below.
168
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -0800169
1703- Renaming classes
171
172This simply changes the name of a class in its definition, as well as all its
173references in internal inner classes and methods.
174Calls from other classes are not modified -- they keep referencing the original
175class name. This allows the bridge to literally replace an implementation.
176
177An example will make this easier: android.graphics.Paint is the main drawing
178class that we need to replace. To do so, the generator renames Paint to _original_Paint.
179Later the bridge provides its own replacement version of Paint which will be used
180by 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
182if it so desires.
183
184Some of the Android classes are basically wrappers over native objects and since
185we don't have the native code in Eclipse, we need to provide a full alternate
186implementation. Sub-classing doesn't work as some native methods are static and
187we don't control object creation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
189This won't rename/replace the inner static methods of a given class.
190
191
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -08001924- Method erasure based on return type
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -0800194This is mostly an implementation detail of the bridge: in the Paint class
195mentioned above, some inner static classes are used to pass around
196attributes (e.g. FontMetrics, or the Style enum) and all the original implementation
197is native.
198
199In this case we have a strategy that tells the generator that anything returning, for
200example, the inner class Paint$Style in the Paint class should be discarded and the
201bridge will provide its own implementation.
202
203
Raphael Moll865c3be2011-06-17 17:12:52 -07002045- Method Delegates
205
206This strategy is used to override method implementations.
207Given a method SomeClass.MethodName(), 1 or 2 methods are generated:
208a- 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.
211b- 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
215The delegate method is a static method.
216If the original method is non-static, the delegate method receives the original 'this'
217as its first argument. If the original method is an inner non-static method, it also
218receives the inner 'this' as the second argument.
219
220
221
Xavier Ducrohet4b52ec42011-02-07 21:08:10 -0800222- References -
223--------------
224
225
226The JVM Specification 2nd edition:
227 http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
228
229Understanding bytecode:
230 http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/
231
232Bytecode opcode list:
233 http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
234
235ASM user guide:
236 http://download.forge.objectweb.org/asm/asm-guide.pdf
237
238
239--
240end