byte code manipulation for android - droidcon paris 2014
Embed Size (px)
DESCRIPTION
http://fr.droidcon.com/2014/agenda/detail?title=Byte+code+manipulation+for+Android+ During the last few years, we have all assisted or participated to a small revolution on Android : annotation processing. Most libs now rely on annotation processing during build to pre-compute a lot of stuff that will boost them at runtime. Let's think about Dagger, ButerKnife, Hugo, RoboGuice, BoundBox, Memento, IcePick, etc. Nevertheless, writing an annotation processor is far from obvious as it offers an API that is very difficult to understand. The main idea of this session is to suggest an alternative technology (or a complement in some cases) : post-compilation processing and byte code manipulation ? This session is an in-depth review of byte code manipulation in Java and its limitations on Android. We will also explore a few techniques and libraries that make it simple to write a post compiler byte code processor, with gradle and maven examples. 2 libraries will be featured during the session : * AfterBurner : * Mimic See how to eliminate all boiler plate from your favorite libraries and boost your apps. Speaker: Stéphane Nicolas, Groupon Stéphane Nicolas is Senior Android Developer at Groupon, specialized in the development of Android applications for smartphones and tablets. With almost 15 years’ experience in Java, he contributed or initiated different Open Source projects for Android (like RoboSpice, RoboDemo, Android Maven Plugin, RoboGuice, etc) or commercial apps. He actively participates to the Android community and contributes to the integration of the Android platform and advanced industrialized programming techniques such as Sonar, Maven, Jenkins, etc.TRANSCRIPT

Byte Code Weaving for Android
and some libs to make it easyMimic AfterBurner Morpheus
lundi 22 septembre 14

Byte Code Weaving for Android
and some libs to make it easyMimic AfterBurner Morpheus
lundi 22 septembre 14

Stéphane NICOLAS
snicolasstephanenicolas +stephane nicolas
Android Senior Developer @ Groupon
BoundBox
And others : RoboDemo, RoboGuice,Quality Analysis Tools for Android, android-maven-plugin, etc..
lundi 22 septembre 14

3
The Android Team is Hiring : https://jobs.groupon.com/careers/
lundi 22 septembre 14

A simple exampleByte Code Weaving for Android
Goal : Log all life cycle methods of an Activity
With LogLifeCycle, you just have to :
Use the LogLifeCycle Gradle plugin inside your build.gradle file
Then simply annotate every activity you wanna log :
https://github.com/stephanenicolas/loglifecycle
apply plugin: 'loglifecycle'
@LogLifeCyclepublic class MainActivity extends Activity {...}
Activity
build.gradle
lundi 22 septembre 14

LogLifeCycleByte Code Weaving for Android
> adb logcat | grep ⟳
D/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onCreateD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onApplyThemeResourceD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onWindowAttributesChangedD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onWindowAttributesChangedD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onWindowAttributesChangedD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onContentChangedD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onAttachFragmentD/LogLifeCycle( 4640): MainActivity$MainFragment [1384183528] ⟳ onCreateD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onStartD/LogLifeCycle( 4640): MainActivity$MainFragment [1384183528] ⟳ onStartD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onTitleChangedD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onPostCreateD/LogLifeCycle( 4640): MainActivity [1384162984] ⟳ onResumeD/LogLifeCycle( 4640): MainActivity$MainFragment [1384183528] ⟳ onResume
lundi 22 septembre 14

Presentation planByte Code Weaving for Android
I. Byte Code Weaving for Android
1) Dynamic Vs. Static Byte Code Weaving2) Why Dynamic Byte Code weaving can’t work on Android3) Transforming classes during Android Post-Compilation build phase 4) Javassist API : much simpler than annotation processing5) Gradle & Maven examples
II. AfterBurner & Mimic : 2 libs to ease Byte Code Weaving on Android
1) Mimic : Templating byte code injection2) Mimic : a simple use case3) AfterBurner : Fluent API for byte code injection4) AfterBurner : a simple use case
lundi 22 septembre 14

Byte Code Weaving for Android
‘‘ Byte Code Weaving is a technique for changing the byte code of compiled
Java classes. ’’
From oracle docs : docs.oracle.com/cd/E17904_01/doc.1111/e16596/bestpractice.htm Section 4.1 Changing Compiled Java Classes with Byte Code Weaving
lundi 22 septembre 14

2 ways to weave Byte Code
Byte Code Weaving for Android
Dynamic Byte Code Weaving at Runtime
Java classes are intercepted prior to being loaded by the class loader.
Byte Code is modified at runtime.
Static Byte Code Weaving at Post Compile Time
Java classes Byte Code is m o d i f i e d r i g h t a f t e r compilation by javac.
Byte Code is modified during build process.
lundi 22 septembre 14

Dynamic Weaving
Byte Code Weaving for Android
Java classes are intercepted prior to being loaded by the class loader.
The interceptor is called a Java agent.
Java agents are defined by a standard API :
•java.lang.instrument.ClassTransformer•java.lang.instrument.Instrumentation
•simple to define agents•no changes to build degrades performance
lundi 22 septembre 14

There are no java agents on Android Dalvik / ART !
Byte Code Weaving for Android
The closest thing to a java agent is an Instrumentation.From stackoverflow.com/q/12725279/693752
lundi 22 septembre 14

What is Java Instrumentation ?
Byte Code Weaving for Android
android.app.Instrumentation API :
•void callActivityOnCreate (Activity activity, Bundle icicle)•void callActivityOnDestroy (Activity activity)•void callActivityOnPause (Activity activity)•void callActivityOnResume (Activity activity)•void callActivityOnStart (Activity activity)•void callActivityOnStop (Activity activity)•void callApplicationOnCreate (Application app)
Android instrumentation is used to pilot application and activities, usually during testing (to provide mocked resources).
lundi 22 septembre 14

Limitations of Instrumentation
Byte Code Weaving for Android
The closest thing to a java agent is an Instrumentation.From stackoverflow.com/q/12725279/693752
Instrumentation :
•is Activity centric•can slow down apps easily•can alter behavior before or after a hook.i.e it can’t fill all your views inflated after setContentView() inside onCreate()setContentView() onCreate()
It is far less powerful than a Java agent.
lundi 22 septembre 14

Byte Code Weaving for Android
There are 2 options to weave Android Byte Code. 1)after compilation by javac and before dexing2)after dexing
Solution 2 requires that we find tools that can read/write Byte Code in the dex format.
Solution 1 offers greater compatibility with existing Java Byte Code manipulation tools.
Post Compilation on Android
lundi 22 septembre 14

Byte Code Weaving for Android
Annotation processing
Post Compilation
Android Build phases
lundi 22 septembre 14

Static Weaving
Byte Code Weaving for Android
For Gradle :• Javassist gradle plugin github.com/darylteo/gradle-plugins
For Maven :• Javassist maven plugin github.com/icon-Systemhaus-GmbH/javassist-maven-plugin
A de facto standard library can be used : Javassist
Highly depends on build tools.
lundi 22 septembre 14

Gradle & MavenJavassist plugins
Byte Code Weaving for Android
Both Javassist gradle & maven plugins share a simple interface to create class transformers :
•void applyTransformations(CtClass classToTransform)•boolean shouldTransform(final CtClass candidateClass)
developers can use them with the build tool of their choice.
https://github.com/stephanenicolas/javassist-build-plugin-api
lundi 22 septembre 14

JavassistByte Code Weaving for Android
Javassist offers :
a very simple API, quite close to Java standard reflection API
it is FAR FAR simpler than annotation processing API
de facto standard for Byte Code manipulation on JVM (used by Jboss, EasyMock, Mockito, JPA implementations, etc.)
it works with everything that interprets Java Byte Code
it cannot manipulate DEX files (see fork: github.com/crimsonwoods/javassist-android)
lundi 22 septembre 14

Byte Code Weaving for Android
A ClassTransformer example
https://github.com/stephanenicolas/afterburner
cd to afterburner-sample-processorsee ExampleProcessor(based on AfterBurner - optional)
lundi 22 septembre 14

Byte Code Weaving for Android
Gradle Byte Code Weaving
https://github.com/stephanenicolas/afterburner
mvn clean installcd after-burner-samplegradle check1 -dgradle check2 -d
lundi 22 septembre 14

Byte Code Weaving for Android
Maven Byte Code Weaving
https://github.com/stephanenicolas/afterburner
mvn clean installcd after-burner-samplemvn clean test
lundi 22 septembre 14

MimicTemplating Byte Code Injection
class Template { public Template() { Log("Inside constr"); } public void doStuff() { Log("Inside doStuff"); }}
class Ancestor { public void doStuff() {}}
@Mimic(sourceClass=Template.class)class Example extends Ancestor { @Override public void doStuff() { super.doStuff(); }}
new Example.doStuff();//logsInside constrInside doStuff
Byte Code Weaving for Android
lundi 22 septembre 14

Fine grain Mimic’ingenum MimicMode { /** Beginning of target method. */ AT_BEGINNING, /** End of target method.*/ BEFORE_RETURN, /** Before a call to an overridden method.*/ BEFORE_SUPER, /** After a call to an overridden method.*/ AFTER_SUPER, /** Instead of a call to an overridden method.*/ REPLACE_SUPER, /** Before a call to a given method.*/ BEFORE, /** After a call to a given method.*/ AFTER;}
Byte Code Weaving for Android
lundi 22 septembre 14

Fine grain Mimic’ing
@Mimic(sourceClass=ExampleTemplate.class, mimicMethods={ @MimicMethod(methodName="doOtherStuff", mode=MimicMode.AT_BEGINNING) })class Example extends ExampleAncestor { @Override void doStuff() { super.doStuff(); } void doOtherStuff() { }}
Byte Code Weaving for Android
lundi 22 septembre 14

Mimic : use caseActivityAndr
oid
Framewor
k
RoboActivityLibra
ry
AppMyRoboActivity
RoboActivity is a complex class that provides nice features : 200 LOCs +.
Byte Code Weaving for Android
Templating Byte Code Injection
lundi 22 septembre 14

Mimic : use case
Library
App
BUT all those classes have the exact same code as RoboActivity.The only difference is their super class.
Byte Code Weaving for Android
RoboActivityRoboFragmentActivity
RoboTabActivityRoboTabActivity
RoboSherlockActivity
RoboActionBarActivityRoboListActivity
RoboActivityRoboFragmentActivity
RoboTabActivityRoboTabActivity
RoboSherlockActivity
RoboActionBarActivityRoboListActivity
Templating Byte Code Injection
lundi 22 septembre 14

Mimic : use caseByte Code Weaving for Android
Templating Byte Code Injection
class RoboActivity extends Activity { void onCreate(Bundle b) {...} void onXXX() {...}}
@RoboActivityclass Example extends WhatEverActivity { @Override void onCreate(Bundle b) { super.onCreate(b); }}
Mimic provides an extensible mechanism to create powerful custom annotations for your libs.
lundi 22 septembre 14

AfterBurnerFluent Byte Code Injection
public class MyActivity { @InjectView TextView textView; @InjectView Button button;
void onCreate(Bundle iCycle) { super.onCreate(iCycle); setContentView(R.layout.mylayout);
//view injection takes place HERE button.setOnClickListener({ textView.setText("Clicked !"); });}
Byte Code Weaving for Android
lundi 22 septembre 14

AfterBurnerFluent Byte Code Injection
builder = new InsertableMethodBuilder(afterBurner); builder .insertIntoClass(classToTransform) .inMethodIfExists("onCreate") .afterACallTo("setContentView") .withBody(createFindViewStatements(classToTransform)) .elseCreateMethodIfNotExists( "public void onCreate(Bundle b) {" + " super.onCreate(b);" + " setContentView(" + <id> + ");" + " ___BODY___ }") .doIt();
Add methods or insert byte code into existing methods.
Byte Code Weaving for Android
lundi 22 septembre 14

Android Specification Requestclass MyActivity extends Activity { @InjectView TextView textView; @InjectView Button button;
protected void onCreate(Bundle iCycle) { super.onCreate(iCycle); setContentView(R.layout.mylayout);
button.setOnClickListener({ textView.setText("Clicked !"); });}
github://TODO
Byte Code Weaving for Android
lundi 22 septembre 14

Open futuresSome ideas that could also become ASRs :
• ButterKnife/RoboGuice -> @InjectView• Dagger/RoboGuice -> @Inject• Otto/RoboGuice/EventBus -> @Observes• Memento/IcePick -> @Statefull• Hugo -> @Log • Wire/Jackson2/gson to generate (de)serialization code for Pojos
• to be continued...
Remove boiler plate from our apps !--> Just code what is worth coding <--
Byte Code Weaving for Android
lundi 22 septembre 14

All those projects are based on Byte Code Weavinghttps://github.com/stephanenicolas/injects
Byte Code Weaving for Android
lundi 22 septembre 14

Android Byte Code Weaving
Remove boiler plate from our apps !
Just code what is worth codinglundi 22 septembre 14

Thanks for your attention.Any questions ?
Any comments ?
Android Byte Code Weaving
lundi 22 septembre 14