lz4/lz4-java

Build Java only library for Android

readysteadygo2006 opened this issue · 7 comments

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:7493_3
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==/split_config.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!

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.

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!

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?

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?

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....

Would you still need any help on this?

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.