Your SlideShare is downloading. ×
  • Like
Taming Java Agents
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Taming Java Agents

  • 6,700 views
Published

A Java agents are pluggable self contained components that run embedded in a JVM and intercept the classloading process. They were introduced in Java 5 along with the powerful java.lang.instrument …

A Java agents are pluggable self contained components that run embedded in a JVM and intercept the classloading process. They were introduced in Java 5 along with the powerful java.lang.instrument package. Java agents can be loaded statically at startup or dynamically (programmatically) at runtime to attach to a running process in a fail-safe fashion.
Java agents were an awesome addition to the JVM as it opened a lot of opportunities for tool designers and changed Java tooling landscape quite drastically. In conjunction with Java bytecode manipulation libraries it is now possible to do amazing things to Java classes: we can experiment with programming models, redefine classes in runtime, record execution flow, etc.
The presentation provides an overview of Java agents’ functionality along with the usage examples and real world experiences. You will learn, how to implement an agent and apply Instrumentation API in combination with bytecode manipulation libraries to solve interesting tasks.

Published in Technology , News & Politics
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
6,700
On SlideShare
0
From Embeds
0
Number of Embeds
35

Actions

Shares
Downloads
63
Comments
0
Likes
11

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Taming  Java  Agents  Anton  Arhipov  ZeroTurnaround,  JRebel  @antonarhipov  
  • 2. -­‐javaagent    java.lang.instrument  
  • 3. java.lang.instrument  import  java.lang.instrument.ClassFileTransformer;  import  java.lang.instrument.InstrumentaBon;   META-INF/MANIFEST.MF   Premain-Class: Agentpublic  class  Agent  {   Agent-Class: Agent      public  staBc  void  premain(String  args,  InstrumentaBon  inst)  {                inst.addTransformer(new  ClassFileTransformer  {  …  });        }        public  staBc  void  agentmain(String  args,  InstrumentaBon  inst)  {              premain(args,  inst);        }  }   java  –javaagent:agent.jar  …  
  • 4. META-­‐INF/MANIFEST.MF  •  Premain-­‐Class  •  Agent-­‐Main  •  Boot-­‐Class-­‐Path  •  Can-­‐Redefine-­‐Classes  •  Can-­‐Retransform-­‐Classes  
  • 5. j.l.instrument.ClassFileTransformer                    byte[]  transform(ClassLoader  loader,                                                                              String  className,                                                                            Class<?>  classBeingRedefined,                                                                            ProtecBonDomain  protecBonDomain,                                                                            byte[]  classfileBuffer);  
  • 6. public  class  MyTransformer  implements  ClassFileTransformer  {                public  void  byte[]  transform(ClassLoader  loader,                                                                              String  className,                                                                            Class<?>  classBeingRedefined,                                                                            ProtecBonDomain  protecBonDomain,                                                                            byte[]  classfileBuffer){                                ClassPool  cp  =  ClassPool.getDefault();                              CtClass  ct  =  cp.makeClass(                                                                            new  ByteArrayInputStream(classfileBuffer));                                  …  …  …                                return  ct.toBytecode();  
  • 7. public  class  MyTransformer  implements  ClassFileTransformer  {                public  void  byte[]  transform(ClassLoader  loader,                                                                              String  className,                                                                            Class<?>  classBeingRedefined,                                                                            ProtecBonDomain  protecBonDomain,                                                                            byte[]  classfileBuffer){                                ClassPool  cp  =  ClassPool.getDefault();                              CtClass  ct  =  cp.makeClass(                                                                            new  ByteArrayInputStream(classfileBuffer));                                  …  …  …     Enter  Javassist!                              return  ct.toBytecode();              
  • 8. public  class  MyTransformer  implements  ClassFileTransformer  {                public  void  byte[]  transform(ClassLoader  loader,                                                                              String  className,                                                                            Class<?>  classBeingRedefined,                                                                            ProtecBonDomain  protecBonDomain,                                                                            byte[]  classfileBuffer){                                ct.addMethod(CtNewMethod.make(                                  "public  void  foo()  {}  ",  ct));                    
  • 9. public  class  MyTransformer  implements  ClassFileTransformer  {                public  void  byte[]  transform(ClassLoader  loader,                                                                              String  className,                                                                            Class<?>  classBeingRedefined,                                                                            ProtecBonDomain  protecBonDomain,                                                                            byte[]  classfileBuffer){                                CtMethod  m  =  ct.getMethod("foo",  "()V");                            m.insertA_er("System.out.println("..")");                    
  • 10. j.l.instrument.InstrumentaBon              void  addTransformer(ClassFileTransformer  transformer,                                                                                          boolean  canRetransform);              void  appendToBootstrapClassLoaderSearch(JarFile  jarfile);            void  appendToSystemClassLoaderSearch(JarFile  jarfile);              Class[]  getAllLoadedClasses();            Class[]  getIniBatedClasses(ClassLoader  loader);                      void  redefineClasses(ClassDefiniBon...  classes);            void  retransformClasses(Class<?>...  classes);            .  .  .  
  • 11. Example  1:  Simple  Trace  public  class  Main  {              public  staBc  void  main(String[]  args)  {                        for  (int  i  =  0;  i  <  args.length;  i++)                                System.out.println(args[i]);              }    }      $  java  Main  1  2  3    1  2  3  
  • 12. Example  1:  Simple  Trace  RULE  trace  main  entry   RULE  trace  main  exit  CLASS  Main   CLASS  Main  METHOD  main   METHOD  main  AT  ENTRY   AT  EXIT  IF  true   IF  true  DO  traceln("entering  main")   DO  traceln("exiBng  main")  ENDRULE   ENDRULE   $  java  –javaagent:byteman.jar=script:trace.btm  Main   entering  main   1   2   3   exiBng  main  
  • 13. Example  2:  Tracing  Threads  for  (int  i  =  0;  i  <  args.length;  i++)  {              final  String  arg  =  args[i];            Thread  thread  =  new  Thread(arg)  {                          public  void  run()  {                                      System.out.println(arg);                        }            };              thread.start();              thread.join();  }  
  • 14. Example  2:  Tracing  Threads  RULE  trace  thread  start    CLASS  java.lang.Thread    METHOD  start()    IF  true    DO  traceln("***  start  for  thread  "  +  $0.getName())    ENDRULE    
  • 15. Example  2:  Tracing  Threads  $    java  -­‐Dorg.jboss.byteman.transform.all          -­‐javaagent:byteman.jar=script:thread.btm,boot:byteman.jar          Main  foo  bar  baz    ***  start  for  thread  foo  foo  ***  start  for  thread  bar  bar  ***  start  for  thread  baz  baz  
  • 16. Example  3:  Side  Effects  RULE  skip  loop  iteraBon  CLASS  Main  METHOD  main  AFTER  CALL  join  IF  ($args[$i]).contains("foo")  DO  $i  =  $i  +  1  ;        traceln("skipping  iteraBon  "  +  $i)  ENDRULE  
  • 17. Example  4:  Arach  to  Process  BufferedReader  in  =  new  BufferedReader(new  InputStreamReader(System.in));  String  next  =  in.readLine();    while  (next  !=  null  &&  next.length()  >  0  &&  !next.contains("end"))  {          final  String  arg  =  next;          Thread  thread  =  new  Thread(arg)  {                    public  void  run()  {                              System.out.println(arg);                    }              };            thread.start();            thread.join();            next  =  in.readLine();  }  
  • 18. Example  4:  Arach  to  Process   $  java  Main   Hello   Hello     $  bminstall.sh  -­‐b  –Dorg…  <PID>   $  bmsubmit.sh  script/ex2.btm     install  rule  trace  thread  start   Test   ***  start  for  thread  Test   Test     $  bmsubmit.sh  -­‐u  script/ex2.btm     uninstall  RULE  trace  thread  start   Test   Test   end   $  
  • 19. Arach  API  VirtualMachine  vm  =  VirtualMachine.arach("2177");    vm.loadAgent("agent.jar",  "arg1=x,arg2=y");    vm.detach();       LimitaBon:  can’t  change  class  schema  
  • 20. Fault  InjecBon   VS   Mocking  
  • 21. Example  5:  Fault  InjecBon  @RunWith(BMUnitRunner.class)  public  class  BytemanJUnitTests  {              @Test(expected=MyServiceUnavailableExcepBon.class)            @BMRule(name="throw  Bmeout  at  1st  call",                                                  targetClass  =  "Socket",                                                  targetMethod  =  "connect",                                                  acBon  =  "throw  new  java.io.IOExcepBon()")                public  void  testErrorInPipeline()  throws  ExcepBon  {                        //  Invokes  internally  Socket.connect(..):                        new  MyHrpClient("hrp://example.com/data").read();              }  }  
  • 22. Example  5:  Fault  InjecBon  @RunWith(BMUnitRunner.class)  public  class  BytemanJUnitTests  {              @Test(expected=MyServiceUnavailableExcepBon.class)            @BMRule(name="throw  Bmeout  at  1st  call",                                                  targetClass  =  "Socket",                                                  targetMethod  =  "connect",                                                  acBon  =  "throw  new  java.io.IOExcepBon()")                public  void  testErrorInPipeline()  throws  ExcepBon  {                        //  Invokes  internally  Socket.connect(..):                        new  MyHrpClient("hrp://example.com/data").read();              }  }  
  • 23. Example  5:  Fault  InjecBon  @RunWith(BMUnitRunner.class)  public  class  BytemanJUnitTests  {              @Test(expected=MyServiceUnavailableExcepBon.class)            @BMRule(name="throw  Bmeout  at  1st  call",                                                  targetClass  =  "Socket",                                                  targetMethod  =  "connect",                                                  acBon  =  "throw  new  java.io.IOExcepBon()")                public  void  testErrorInPipeline()  throws  ExcepBon  {                        //  Invokes  internally  Socket.connect(..):                        new  MyHrpClient("hrp://example.com/data").read();              }  }  
  • 24. Example  5:  Fault  InjecBon  @RunWith(BMUnitRunner.class)  public  class  BytemanJUnitTests  {              @Test(expected=MyServiceUnavailableExcepBon.class)            @BMRule(name="throw  Bmeout  at  1st  call",                                                  targetClass  =  "Socket",                                                  targetMethod  =  "connect",                                                  acBon  =  "throw  new  java.io.IOExcepBon()")                public  void  testErrorInPipeline()  throws  ExcepBon  {                        //  Invokes  internally  Socket.connect(..):                        new  MyHrpClient("hrp://example.com/data").read();              }  }  
  • 25. Example  5:  Fault  InjecBon  @RunWith(BMUnitRunner.class)  public  class  BytemanJUnitTests  {              @Test(expected=MyServiceUnavailableExcepBon.class)            @BMRule(name="throw  Bmeout  at  1st  call",                                                  targetClass  =  "Socket",                                                  targetMethod  =  "connect",                                                  acBon  =  "throw  new  java.io.IOExcepBon()")                public  void  testErrorInPipeline()  throws  ExcepBon  {                        //  Invokes  internally  Socket.connect(..):                        new  MyHrpClient("hrp://example.com/data").read();              }  }  
  • 26. @Path("/")  public  String  foo()  {      return  "FooBar";  }  
  • 27. @Path("/")  public  String  foo()  {      return  "FooBar";  }   @Path("/")   public  FooBar  foo()  {      return  new  FooBar();   }  
  • 28. @Path("/")  public  String  foo()  {      return  "FooBar";  }   @Path("/foobar")   public  FooBar  foo()  {      return  new  FooBar();   }  
  • 29. JRebel   Make  changes  in  IDE   OldClassLoaderFramework   MyObject.class   Code   101000101   100010010   New  code   JRebel   111000100   101010010   MyObject ConfiguraDon   (XML,  annotaDons,..)  
  • 30. java  –javaagent:jrebel.jar  App  
  • 31. Chronon  •  A  back-­‐in-­‐Bme  debugger  for  Java   –  Recording  a  program  execuBon   –  Debugging  the  recording  •  What  is  recorded?   –  Variable  history   –  Method  calls   –  ExcepBons   –  Console  output   –  Threads  
  • 32. Memory  buffer   Recorded  data   Flusher  threads  ApplicaBon  threads   Recording  
  • 33. java  -­‐javaagent:recorder.jar=config.txt  
  • 34. Recording  Local  Variable  Changes  •  Just  a  brute-­‐force  idea:   –  Instrument  *store  (astore,  istore,  etc)  instrucBons   to  write  the  value  to  a  store   int  i  =  2;   iconst_2   iconst_2   istore_1   istore_1   iload_1   invokestaBc  …  
  • 35. Plumbr:  Memory  leak  detecBon  •  RunBme  applicaBon  analysis   –  vs  post-­‐mortem  heap  dump  analysis   –  vs  profilers  –  human  operated,  rarely  usable  in   producBon  •  AdapBve  introspecBon   –  Monitor  high  level  metrics,  cheap  to  obtain   –  Collect  expensive  detailed  informaBon  when   suspects  are  found  
  • 36. Plumbr  •  Memory  leak  in  Java  –  some  objects  are   created  Bme  a_er  Bme  but  a  reference  is   forgoren  •  Look  at  when  object  was  created  and  how   long  it  lives    
  • 37. What  is  leaking?  Time (garbage collection cycles)Instances of a class that belong to base application framework:Class instances that handle user interaction:Common JDK class instances:Instances of a leaking class:
  • 38. -­‐javaagent    java.lang.instrument  
  • 39. @antonarhipov  anton@zeroturnaround.com