Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RangedBeacon getFilter() #1164

Open
NikolaHadzicNs opened this issue Oct 18, 2023 · 13 comments
Open

RangedBeacon getFilter() #1164

NikolaHadzicNs opened this issue Oct 18, 2023 · 13 comments

Comments

@NikolaHadzicNs
Copy link

Hi, I have problem with range beacons. Lib crash on getFilter().addMeasurement(rssi);

Expected behavior

If filter not specified use default filter (protected static Class rssiFilterImplClass = RunningAverageRssiFilter.class;)

Actual behavior

private RssiFilter getFilter() {
if (mFilter == null) {
//set RSSI filter
try {
Constructor cons = BeaconManager.getRssiFilterImplClass().getConstructors()[0];
mFilter = (RssiFilter)cons.newInstance();
} catch (Exception e) {
LogManager.e(TAG, "Could not construct RssiFilterImplClass %s", BeaconManager.getRssiFilterImplClass().getName());
}
}
return mFilter;
}
BeaconManager.getRssiFilterImplClass().getConstructors()[0] with exception java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
returns null and app crash on getFilter().addMeasurement(rssi);

Steps to reproduce this behavior

Start ranging for beacons

Mobile device model and OS version

Samsung 20fe android 12
Xiaomi poco f1 android 10

Android Beacon Library version

2.19.5

Is there a problem compile with java version 17? This is my only change in configuration.

Thanks for taking a look :)

@NikolaHadzicNs
Copy link
Author

Quick fix for me is to instance filter directly:

private RssiFilter getFilter() {
if (mFilter == null) {
//set RSSI filter
try {
Constructor cons = BeaconManager.getRssiFilterImplClass().getConstructors()[0];
mFilter = (RssiFilter)cons.newInstance();
} catch (Exception e) {
LogManager.e(TAG, "Could not construct RssiFilterImplClass %s", BeaconManager.getRssiFilterImplClass().getName());
mFilter = new RunningAverageRssiFilter();
}
}
return mFilter;
}

@t0k4rt
Copy link

t0k4rt commented Feb 23, 2024

@NikolaHadzicNs We encounter almost the same issue on lib version 2.9.6
Are you still using a patched version ? Or did you find the culprit ? Might indeed be related to the java version

Fatal Exception: java.lang.NullPointerException: throw with null exception
       at org.altbeacon.beacon.service.RangedBeacon.addMeasurement(RangedBeacon.java:79)
       at org.altbeacon.beacon.service.RangedBeacon.updateBeacon(RangedBeacon.java:39)
       at org.altbeacon.beacon.service.RangedBeacon.<init>(RangedBeacon.java:29)
       at org.altbeacon.beacon.service.RangeState.addBeacon(RangeState.java:61)
       at org.altbeacon.beacon.service.ScanHelper.processBeaconFromScan(ScanHelper.java:372)
       at org.altbeacon.beacon.service.ScanHelper$ScanProcessorRunnable.run(ScanHelper.java:455)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:764)

@NikolaHadzicNs
Copy link
Author

@t0k4rt Yes, I am still using the patched version. For me problem was this line from RangedBeacon class:

Constructor cons = BeaconManager.getRssiFilterImplClass().getConstructors()[0];
So I added creation of filter in catch:

private RssiFilter getFilter() { if (mFilter == null) { //set RSSI filter try { Constructor cons = BeaconManager.getRssiFilterImplClass().getConstructors()[0]; mFilter = (RssiFilter)cons.newInstance(); } catch (Exception e) { LogManager.e(TAG, "Could not construct RssiFilterImplClass %s", BeaconManager.getRssiFilterImplClass().getName()); mFilter = new RunningAverageRssiFilter(); } } return mFilter; }

It is not the perfect solution but works for me...

@davidgyoung
Copy link
Member

Does this problem happen out-of-the-box without configuring a custom RssiFilter?

Does it happen 100% of the time in your app or just on some devices?

Has it been seen in the wild in crash reports or just on test devices?

@t0k4rt
Copy link

t0k4rt commented Feb 23, 2024

@davidgyoung For us it's out of the box (no custom rssi filter), it does unfortunately not happen on test devices.
According to our stats, it happens mainly on Android 8/9 (80% of the crashes) and mainly samsung (80%)
But it triggers 500 crashes every days which is a lot for us.

I've got no Android 8/9 device to test I'll try to procure one.

@NikolaHadzicNs
Copy link
Author

@davidgyoung For me it was happening out of the box.
No custom filter set for library.
It was happening only on:
Samsung 20fe android 12
Xiaomi poco f1 android 10
I wasn't tested on other devices.

@davidgyoung
Copy link
Member

I tried calling the same code that caused the crash from the Kotlin reference application, and ran it on an Android 8 simulator, but it did not crash.

@t0k4rt
Copy link

t0k4rt commented Feb 26, 2024

I cannot reproduce too with the reference app, I'm still investigating.
But, there is still a problem with that part of code because as is, there is the possbiility of an undefined behaviour.
When rssi filter fail to instantiate, getFilter will return null and lead to a null pointer exception.
Would you be open to a small refactoring on this part to mitigate this undefined behaviour ?

@davidgyoung
Copy link
Member

Sure, I am open to refactoring this, but the API needs to stay the same. Right now the way that API works is that you pass your custom class to:

BeaconManager.setRssiFilterImplClass( ... )

which overrides the default:

protected static Class rssiFilterImplClass = RunningAverageRssiFilter.class;

And this gets instantiated by calling the constructor via reflection when needed.

Perhaps there is a different more stable to call the constructor via reflection?

@t0k4rt
Copy link

t0k4rt commented Feb 28, 2024

@davidgyoung Tell me what you think (#1181). With this PR, you can still pass a custom RSSIFilter, but if there is an issue during class instantiation, it will fallback to RunningAverageRssiFilter and it should avoid any nullpointer exception.

I also used class.newInstance() instead of using the constuctor since with the current implementation, you cannot pass parameters when you instantiate the rssi filter class (and this is the goal of the constructor class).

I tried this change on the reference app, it works as expected.

@davidgyoung
Copy link
Member

Thanks @t0k4rt, I marked #1181. I have at least one other change I need to get into the next bug fix release, then expect to roll one next week.

@robertarone
Copy link

robertarone commented Apr 5, 2024

We had the same issue after updating our app. Our app would keep crashing when doing a scan, specifically:

org.altbeacon.beacon.service.RangedBeacon.addMeasurement
java.lang.NullPointerException

org.altbeacon.beacon.service.RangedBeacon.commitMeasurements
java.lang.NullPointerException

Our developers could not recreate the issue when testing through Android Studio. After speaking with David, we were able to get the app to crash when installing directly from the Play Store. We were then able to get the app to crash by changing our debug build settings to the same as our release. Specifically, this setting:

minifyEnabled: true

caused the app to crash. We do not believe it is device dependent as it has happened on several Samsung Galaxy devices as well as Google Pixel devices

Update:

It looks like Proguard wasn't able to handle the class properly. We added the following line to the proguard-rules.pro file located inside app folder (The problem disappeared as a fix for now while keeping minifyEnabled: true):

-keep class org.altbeacon.beacon.service.** { *; }

@davidgyoung
Copy link
Member

The code that crashes uses Java reflection to instantiate the RunningAvrerageRssiFilter class by name, the default name is stored as a String in side the library. So it would make sense for any minification or obfuscation that changes the class names to cause this to happen.

The funny thing is that I would think this problem would have popped up many years ago -- that code has been present in the library since 2015. Something must have changed in newer Android build tools to start this happening now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants