App: [HOLD for payment 2023-05-03] [$1000] [Crash] Investigate EventEmitter.addEvent on Android

Problem

coming from https://console.firebase.google.com/u/0/project/expensify-chat/crashlytics/app/android:com.expensify.chat/issues/4bd625f86a63554f09e632520a29dfe5?time=last-seven-days&sessionEventKey=643856AC016C00010CA3E2063908E8E8_1800062918688317541

in version 1.2.99-6 we are running into this error on Android, on mostly Sony devices related to the urban airship

Fatal Exception: java.lang.NoSuchMethodError: No interface method putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; in class Ljava/util/Map; or its super classes (declaration of 'java.util.Map' appears in /system/framework/core-libart.jar)
       at com.urbanairship.android.framework.proxy.events.EventEmitter.addEvent(EventEmitter.kt:32)
       at com.urbanairship.android.framework.proxy.AirshipListener.onInboxUpdated(AirshipListener.kt:123)
       at com.urbanairship.messagecenter.Inbox$9.run(Inbox.java:763)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:211)
       at android.app.ActivityThread.main(ActivityThread.java:5371)
       at java.lang.reflect.Method.invoke(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:945)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:740)

Why is it important

Its causing app to crash

solution

Investigate and try to fix this crash

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~01ef230aad8534b92a
  • Upwork Job ID: 1648082798749863936
  • Last Price Increase: 2023-04-17

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 38 (24 by maintainers)

Most upvoted comments

@akinwale I am updating the code to remove putIfAbsent so it will be backwards compatible.

We cant just do a simple put since the code is tracking pending events that the plugin is unable to send yet (no listener). The list is needed since we might have multiple events of the same type. Your proposal of doing a check for null first would of worked, but since we are in Kotlin I used a handy getOrPut method. Here is the change - https://github.com/urbanairship/airship-mobile-framework-proxy/pull/7/files

I will have a fix out today, so I think the path forward is to just wait for the release and update to resolve this issue.

Oh wait, you already did. Okay, cool. I’m just a money man. 😄

Paid!

Offer resent to the correct profile!

Thanks for the bump @akinwale. Looks like this was unblocked for payment yesterday.

@twisterdotcom @rushatgabhane I checked off all the regression items because the regression occurred on an external library.

Thanks for the speedy update Ryan!

Okay, @akinwale would you like to update your proposal to simply update the library?

Airship 15.2.3 release is out

Thanks for the report, ill get this resolved this week.

@akinwale Great find! Just to confirm, https://github.com/urbanairship/airship-mobile-framework-proxy is the repo where the bug is present?

The repo seems really active. It should be an easy fix.

Yes. From line 32 of the EventEmitter class.

Proposal

Please re-state the problem that we are trying to solve in this issue.

There is an app crash on mostly Sony devices related to urban airship.

What is the root cause of that problem?

The source of the problem is the putIfAbsent method being called by the airship-mobile-framework package.

https://github.com/urbanairship/airship-mobile-framework-proxy/blob/3e9cf017e4b878f21afccaf103658e9b882dc13f/android/airship-framework-proxy/src/main/java/com/urbanairship/android/framework/proxy/events/EventEmitter.kt#L32

The putIfAbsent method was introduced in API Level 24 (Android 7) according to the documentation for java.util.Map which is the base interface for maps. Trying to execute this on a device which is running a version of Android prior to 7 will result in this error. Thus, it makes sense that mostly Sony devices would be affected they haven’t been diligent with major Android software updates. To verify, check the crash version being reported by Firebase.

What changes do you think we should make in order to solve the problem?

Update: With the release of react-native-airship 15.2.3 which incorporates a fix for the problem, we can simply update package.json with the new version number.

https://github.com/Expensify/App/blob/f54a8bd23018644d33114d1820f7e428f18c74f9/package.json#L67

We can either propose a change upstream to fix the issue. Changing the putIfAbsent call to just put should be adequate, since it’s simply adding a key/value pair to a map, and if the key already exists, it will be overwritten. If it’s absolutely necessary to check that the key exists, then we can use a combination of a !containsKey or get(key) == null check, and if the key doesn’t exist or the key value is null, use the put method to add the key/value pair to the map.

Alternatively, if the change cannot be applied upstream, maintain a fork of the airship-mobile-framework-proxy package. This is a dependency for the react-native-airship package, so a fork of this would have to be maintained as well.

https://github.com/urbanairship/react-native-airship/blob/main/android/build.gradle#L153

What alternative solutions did you explore? (Optional)

This would be more restrictive, but it’s possible to set 24 as the minSdkVersion for Android builds. This would prevent the app from being installed on devices running older versions of Android.