lz4 / lz4-java

LZ4 compression for Java
Apache License 2.0
1.1k stars 253 forks source link

Build Java only library for Android #130

Closed readysteadygo2006 closed 4 years ago

readysteadygo2006 commented 5 years ago

Hi,

I'm trying to build the lz4-java library for use on the Android platform. My development environment is Gradle based.

I've tried to build it by running the ANT build scripts on Linux to generate the templated files created at build time, then copied these into the lz4 and util directories respectviely. Whilst this allows me to build the project, I get runtime error of the form shown below:

2018-11-23 18:11:52.581 7493-7522/? E/AndroidRuntime: FATAL EXCEPTION: Binder:74933 Process: no.nordicsemi.android.nrfblinky, PID: 7493 java.lang.AssertionError: java.lang.ClassNotFoundException: Didn't find class "net.jpountz.lz4.LZ4JavaSafeCompressor" on path: DexPathList[[zip file "/data/app/no.nordicsemi.android.nrfblinky-S9Z7owDv-T4H1X3fhCH-A==/base.apk", zip file "/data/app/no.nordicsemi.android.nrfblinky-S9Z7owDv_-T4H1X3fhCH-A==/splitconfig.xxxhdpi.apk"],nativeLibraryDirectories=[/data/app/no.nordicsemi.android.nrfblinky-S9Z7owDv-T4H1X3fhCH-A==/lib/arm64, /system/lib64, /vendor/lib64]] at net.jpountz.lz4.LZ4Factory.instance(LZ4Factory.java:53) at net.jpountz.lz4.LZ4Factory.safeInstance(LZ4Factory.java:98) at net.jpountz.lz4.LZ4Factory.fastestJavaInstance(LZ4Factory.java:134) at net.jpountz.lz4.LZ4Factory.fastestInstance(LZ4Factory.java:162) at net.jpountz.BufferMgr.BufferMgr.decompDecompress(BufferMgr.java:126) at no.nordicsemi.android.blinky.profile.BlinkyManager$1.onCharacteristicNotified(BlinkyManager.java:299) at no.nordicsemi.android.ble.BleManager$BleManagerGattCallback.onCharacteristicChanged(BleManager.java:1440) at android.bluetooth.BluetoothGatt$1$8.run(BluetoothGatt.java:443) at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:725) at android.bluetooth.BluetoothGatt.-wrap0(Unknown Source:0) at android.bluetooth.BluetoothGatt$1.onNotify(BluetoothGatt.java:437) at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:184) at android.os.Binder.execTransact(Binder.java:697)

I've switched from using fastestInstance() to use fastestJavaInstance().

Don't really understand why LZ4JavaSafeCompressor is being referenced from: net.jpountz.lz4.LZ4JavaSafeCompressor as in my final effort I've changed all packages to be rooted under project, none of files in project mention net.jpountz, but still get class reference error.

I'd be happy with a "blessed" way to build for Android or a fix to my approach.

Hope you can help!

odaira commented 5 years ago

I am not familiar with Android at all, but have you tried the jar-no-jni target of the ant build script? It will build a java-only library, although I have never tried it for Android.

readysteadygo2006 commented 5 years ago

Hi,

Was really confused with persisting references to net.jountz, so deleted build directory completely and rebuilt project. I still get error, but now references are to the correct hierachy:

2018-11-25 13:33:39.482 1309-1335/no.nordicsemi.android.nrfblinky E/JavaBinder: *** Uncaught remote exception! (Exceptions are not yet supported across processes.) java.lang.AssertionError: java.lang.ClassNotFoundException: Didn't find class " no.nordicsemi.android.blinky.lz4.LZ4JavaSafeCompressor" on path: DexPathList[[zip file "/data/app/no.nordicsemi.android.nrfblinky-mf7hIzpoBFHfXlG-cWhpYw==/base.apk", zip file "/data/app/no.nordicsemi.android.nrfblinky-mf7hIzpoBFHfXlG-cWhpYw==/split_config.xxxhdpi.apk"],nativeLibraryDirectories=[/data/app/no.nordicsemi.android.nrfblinky-mf7hIzpoBFHfXlG-cWhpYw==/lib/arm64, /system/lib64, /vendor/lib64]] at no.nordicsemi.android.blinky.lz4.LZ4Factory.instance(LZ4Factory.java:54) at no.nordicsemi.android.blinky.lz4.LZ4Factory.safeInstance(LZ4Factory.java:99) at no.nordicsemi.android.blinky.lz4.LZ4Factory.fastestJavaInstance(LZ4Factory.java:135) at no.nordicsemi.android.blinky.BufferMgr.BufferMgr.decompDecompress(BufferMgr.java:128) at no.nordicsemi.android.blinky.profile.BlinkyManager$1.onCharacteristicNotified(BlinkyManager.java:306) at no.nordicsemi.android.ble.BleManager$BleManagerGattCallback.onCharacteristicChanged(BleManager.java:1440) at android.bluetooth.BluetoothGatt$1$8.run(BluetoothGatt.java:443) at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:725) at android.bluetooth.BluetoothGatt.-wrap0(Unknown Source:0) at android.bluetooth.BluetoothGatt$1.onNotify(BluetoothGatt.java:437) at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:184) at android.os.Binder.execTransact(Binder.java:697)

Hopefully this will avoid time being wasted on the reference mismatch I mentioned above!

odaira commented 5 years ago

Looks like it is simply because the LZ4JavaSafeCompressor class is not in your CLASSPATH...? Have you checked it is really in your build?

Your build process looks uncommon, so I have no idea how you copied the files and built them, but the private constructor of the LZ4FactoryClass has hard-coded references to the net.jpountz.lz4. classes. I am wondering how it refers to no.nordicsemi.android.blinky.. Did you rewrite the code?

readysteadygo2006 commented 5 years ago

Hi, Thanks for taking time to respond!

Of course your right LZ4FactoryClass has hard coded paths for loading classes at line 184: fastCompressor = classInstance("net.jpountz.lz4.LZ4" + impl + "Compressor"); highCompressor = classInstance("net.jpountz.lz4.LZ4HC" + impl + "Compressor"); fastDecompressor = classInstance("net.jpountz.lz4.LZ4" + impl + "FastDecompressor"); safeDecompressor = classInstance("net.jpountz.lz4.LZ4" + impl + "SafeDecompressor"); I've changed these to have paths appropriate for my hierarchy: no.nordicsemi.android.blinky

Additionally I run the ANT script on Linux, to generate the files: under LZ4: LZ4HCJavaSafeCompressor.java
LZ4JavaSafeFastDecompressor.java
LZ4JavaUnsafeFastDecompressor.java LZ4HCJavaUnsafeCompressor.java
LZ4JavaSafeSafeDecompressor.java
LZ4JavaUnsafeSafeDecompressor.java LZ4JavaSafeCompressor.java
LZ4JavaUnsafeCompressor.java

and under xxhash: StreamingXXHash32JavaSafe.java
StreamingXXHash64JavaSafe.java
XXHash32JavaSafe.java
XXHash64JavaSafe.java StreamingXXHash32JavaUnsafe.java
StreamingXXHash64JavaUnsafe.java
XXHash32JavaUnsafe.java
XXHash64JavaUnsafe.java

I copy these files to my hieararchy, however it seems that the runtime class loader still does not find the classes.

Can I just compile time instantiate the compressors/decompressors like: Changing: fastCompressor = classInstance(" no.nordicsemi.android.blinky.lz4.LZ4" + impl + "Compressor"); to: fastCompressor = new LZ4JavaSafeCompressor(); Would this work?

Does the constructor need parameters? Does anything else need to be done?

odaira commented 5 years ago

I would refer to the static INSTANCE field of each class, e.g. fastCompressor = LZ4JavaSafeCompressor.INSTANCE; but I am not sure if it works correctly.

As I said before, I am still wondering why you do not try to use the jar-no-jni target of the build script. Is there any reason you want to place all the LZ4 classes in your hierarchy no.nordicsemi.android.blinky.*, not in net.jpountz.lz4.*? If this is a common problem in Android, I am happy to more seriously support and test the jar-no-jni target, but copying the source files to your hierarchy is definitely out of my support scope, so all I can do is just to give you some advice....

odaira commented 4 years ago

Would you still need any help on this?

kevlahnota commented 4 years ago

I hope this helps for android builds. LZ4-java is working fine for android (just tested 1.7.1 version), you just need to define in your proguard.cfg -keep class net.jpountz.** { *; } so when you build for android, it will not delete the necessary classes.