4

I am developing an Android app with a 3rd-party library. I want to replace a method call in the library. Please note that I cannot obtain the library's source code, so that I have to change it at runtime.

For example, let's assume there is doA() method in a class Foo in the library

class Foo {
    doA() {
        //method body
    }
    ...
}

I want to replace the method body of doA() with my own code. I have done some exploration and found the following stackoverflow thread: Replacing a method call in a class at runtime. The thread tells me that I may try a bytecode manipulation library called javassist. I found there is an Android-version of that library at here: https://github.com/crimsonwoods/javassist-android. I imported the library and wrote following code:

try {
    final ClassPool cp = ClassPool.getDefault(getApplicationContext());
    CtClass cc = cp.get("Foo");
    CtMethod method = cc.getMethod("doA","()V");
    method.setBody("{ java.lang.System#out.println(\"doA() is called.\");}");
    cc.writeFile();     //where the exception was raised        
} catch (Exception e) {
    e.printStackTrace();
}

But I encountered an exception when executing cc.writeFile(). It is "FileNotFoundException: ./Foo.class: open failed: ENOENT (No such file or directory)". I do not know how to address this problem.

Community
  • 1
  • 1
user3598016
  • 41
  • 1
  • 2
  • not every class is available to every android sdk version, on some devices this may work, and on some you'll get an exception – Lena Bru Jun 26 '14 at 17:58
  • why not use a boolean variable at runtime – Illegal Argument Jun 26 '14 at 17:58
  • Not having source code != having to change it at runtime. You're much better off modifying the library statically if at all possible, since dynamic code modification is not only more complicated, but it looks suspicious to virus scanners too. – Antimony Jun 27 '14 at 02:46
  • Good point, Antimony. But I want to edit it at runtime so that I don't have to do it again next time the library is upgraded. If statically change the bytecode, I may have to do it again when the library upgrades. – user3598016 Jun 27 '14 at 05:12

1 Answers1

1

Your code is probably trying to save new class file which is not possible. There are huge differences between Java and Android as Android is not using normal .class files but .dex file instead.

You should follow this sample: https://github.com/crimsonwoods/javassist-android/blob/master/javassistSample/src/org/jamruby/javassistsample/MainActivity.java

Václav Hodek
  • 638
  • 4
  • 9
  • Vaclav, thanks for the point. I followed the example but found another problem. My class is very complex. The instrumentation failed at line 56, which is to call DexFile.addClass(). I debugged it and it gets to very deep of the javassist code that I don't understand. I guess the current implementation of javassist cannot handle such as complex classes. – user3598016 Jun 27 '14 at 05:14