Skip to content

MessageBuffer doesn't work on Android OS #101

Closed

Description

@komamitsu

I used MessageBuffer on Android OS(4.0.3) simulator. But these error and exceptions occurred.

05-25 02:36:36.306: E/dalvikvm(12569): Could not find class 'sun.nio.ch.DirectBuffer', referenced from method org.msgpack.core.buffer.MessageBuffer.putByteBuffer
05-25 02:36:36.347: E/AndroidRuntime(12569): FATAL EXCEPTION: main
05-25 02:36:36.347: E/AndroidRuntime(12569): java.lang.ExceptionInInitializerError
05-25 02:36:36.347: E/AndroidRuntime(12569):    at com.example.TestApp.MyActivity.onResume(MyActivity.java:186)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1185)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.Activity.performResume(Activity.java:5182)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2732)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2771)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2235)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.ActivityThread.access$600(ActivityThread.java:141)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.os.Handler.dispatchMessage(Handler.java:99)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.os.Looper.loop(Looper.java:137)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at android.app.ActivityThread.main(ActivityThread.java:5041)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at java.lang.reflect.Method.invokeNative(Native Method)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at java.lang.reflect.Method.invoke(Method.java:511)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at dalvik.system.NativeStart.main(Native Method)
05-25 02:36:36.347: E/AndroidRuntime(12569): Caused by: java.lang.RuntimeException: java.lang.NoSuchFieldException: theUnsafe
05-25 02:36:36.347: E/AndroidRuntime(12569):    at org.msgpack.core.buffer.MessageBuffer.<clinit>(MessageBuffer.java:77)
05-25 02:36:36.347: E/AndroidRuntime(12569):    ... 16 more
05-25 02:36:36.347: E/AndroidRuntime(12569): Caused by: java.lang.NoSuchFieldException: theUnsafe
05-25 02:36:36.347: E/AndroidRuntime(12569):    at java.lang.Class.getDeclaredField(Class.java:631)
05-25 02:36:36.347: E/AndroidRuntime(12569):    at org.msgpack.core.buffer.MessageBuffer.<clinit>(MessageBuffer.java:32)
05-25 02:36:36.347: E/AndroidRuntime(12569):    ... 16 more

I think it's not an urgent issue for now. I created this issue just FYI.

Activity

  1. added this to the v07 milestone on May 25, 2014
  2. added a commit that references this issue on May 26, 2014
  3. xerial commented on May 26, 2014

    @xerial
    Member

    Added a workaround for Android OS. @komamitsu Could you test this?

  4. added a commit that references this issue on May 26, 2014
  5. xerial commented on May 26, 2014

    @xerial
    Member

    Unsafe instance can be found by the previous commits. The next problem is to create DirectByteBuffer instances. It looks like the constructor of DirectByteBuffer is different between Android OS and Oracle JVM.

  6. xerial commented on May 26, 2014

    @xerial
    Member
  7. xerial commented on May 26, 2014

    @xerial
    Member

    And also sun.misc.Unsafe API is slightly different from Oracle JVM:
    https://android.googlesource.com/platform/libcore/+/master/libdvm/src/main/java/sun/misc/Unsafe.java

  8. xerial commented on May 26, 2014

    @xerial
    Member

    Unsafe class in Android has not getByte(address). Instead I found libcore.io.Memory.peekByte(address):
    https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/io/Memory.java

  9. xerial commented on May 26, 2014

    @xerial
    Member

    We cannot access libcore.io package and DirectByteBuffer class without using reflection. So we should provide a fallback that only uses byte[] or ByteBuffer based access methods to memory.

  10. added a commit that references this issue on May 26, 2014
  11. timnew commented on Jan 14, 2015

    @timnew

    Is there any update about this issue? I encounters exactly same issue.

  12. xerial commented on Jan 15, 2015

    @xerial
    Member

    I'll add MessageBufferU(niversal) class, which does not depend on Unsafe and DirectByteBuffer classes.

  13. axeon commented on Jan 19, 2015

    @axeon

    @xerial
    Thanks for your work on android support.

    String bufferClsName;
    if(isJavaAtLeast7) {
    if(isLittleEndian)
    bufferClsName = "org.msgpack.core.buffer.MessageBuffer";
    else
    bufferClsName = "org.msgpack.core.buffer.MessageBufferBE";
    }
    else {
    bufferClsName = "org.msgpack.core.buffer.MessageBufferU";
    }

    the code above , change to org.msgpack.core.buffer.MessageBufferX.class is better.
    It can't be used for proguard, when you use class String.

  14. xerial commented on Jan 19, 2015

    @xerial
    Member

    @axeon
    The above switch is necessary for avoiding generation of TypeProfile for MessageBuffer methods, which is a key to achieve good performance in platform other than Android.

    Is there any option in proguard to force include MessageBufferU class?

  15. xerial commented on Jan 19, 2015

    @xerial
    Member
  16. axeon commented on Jan 19, 2015

    @axeon

    @xerial
    the new version is ok on android, but logcat print too many exception such as "can't find class sun.nio.ch.DirectBuffer/sun.misc,Unsafe".
    on andorid platform ,the java.specification.version is 0.9.

    I think we can add MessageBufferFactory or other class to switch MessageBuffer class, it will be disable class not found exception .

    In addition ,these code is tested in android .

           Class<?> bufferCls = null;
            if(isJavaAtLeast7) {
                if(isLittleEndian)
                    bufferCls = org.msgpack.core.buffer.MessageBuffer.class;
                else
                    bufferCls = org.msgpack.core.buffer.MessageBufferBE.class;
            }
            else {
                bufferCls = org.msgpack.core.buffer.MessageBufferU.class;
            }
    
            msgBufferClass = bufferCls;
    
  17. xerial commented on Jan 19, 2015

    @xerial
    Member

    @axeon
    Our design decision is that we never create any interface for MassageBuffer class, because interface adds overhead to every method call due to invokeinterface call and TypeProfile generation. Speed has been the most important factor in designing msgpack v07.

    Even if we create a factory class, it still needs to load MessageBuffer class (since it is a base class) and will show the warning messages you observed.

    Thanks for java.specification.version information. The msgpack-core-0.7.0-p4 now uses isAndroid flag:

  18. axeon commented on Jan 19, 2015

    @axeon

    @xerial
    Thanks for your works.
    Maybe we can use MessageBufferU as base class, when detected optimized conditions is ok, then switch to MessageBufferOpt(MessageBuffer now).
    This solution will be balanced performance and aesthetic design .

  19. xerial commented on Jan 19, 2015

    @xerial
    Member

    @axeon
    FYI. If JVM finds two or more classes that defines a method, it will generate TypeProfile. Simply writing import MessageBufferU in a code results in generation of TypeProfile and ends up slowing down method calls of MessageBuffer.

    So we cannot make MessageBufferU.getByte a base class of MessageBuffer.getByte.

    For reducing warning message, we should create a different ticket and maybe worth considering to create a separate build for Android platform.

    Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions