byte code manipulation for android - droidcon paris 2014

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

Upload: paris-android-user-group

Post on 25-Jun-2015

596 views

Category:

Technology


0 download

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

Page 1: Byte Code Manipulation for Android - Droidcon Paris 2014

Byte Code Weaving for Android

and some libs to make it easyMimic AfterBurner Morpheus

lundi 22 septembre 14

Page 2: Byte Code Manipulation for Android - Droidcon Paris 2014

Byte Code Weaving for Android

and some libs to make it easyMimic AfterBurner Morpheus

lundi 22 septembre 14

Page 3: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 4: Byte Code Manipulation for Android - Droidcon Paris 2014

3

The Android Team is Hiring : https://jobs.groupon.com/careers/

lundi 22 septembre 14

Page 5: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 6: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 7: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 8: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 9: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 10: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 11: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 12: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 13: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 14: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 15: Byte Code Manipulation for Android - Droidcon Paris 2014

Byte Code Weaving for Android

Annotation processing

Post Compilation

Android Build phases

lundi 22 septembre 14

Page 16: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 17: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 18: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 19: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 20: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 21: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 22: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 23: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 24: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 25: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 26: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 27: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 28: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 29: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 30: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 31: Byte Code Manipulation for Android - Droidcon Paris 2014

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

Page 32: Byte Code Manipulation for Android - Droidcon Paris 2014

All those projects are based on Byte Code Weavinghttps://github.com/stephanenicolas/injects

Byte Code Weaving for Android

lundi 22 septembre 14

Page 33: Byte Code Manipulation for Android - Droidcon Paris 2014

Android Byte Code Weaving

Remove boiler plate from our apps !

Just code what is worth codinglundi 22 septembre 14

Page 34: Byte Code Manipulation for Android - Droidcon Paris 2014

Thanks for your attention.Any questions ?

Any comments ?

Android Byte Code Weaving

lundi 22 septembre 14