Missing Android proguard code throws a NullPointerException when it really shouldn't be

I have distributed the application on the Android Marketplace. I get error reports from a small part of users (maybe 2%), where they get NullPointerExceptions, where this makes no logical sense.

I could never reproduce it myself. The code is relatively simple and is a common code path that every user must follow. I actually took every single line of code that could create an NPE and wrap it in a try-catch block and throw a custom runtime exception, but I still get NullPointerException errors that were not detected.

At this moment, the only thing I can imagine is something related to my involvement with Proguard. I saw how some other articles talked about taking out the -overloadaggressively option if you noticed strange behavior, but as far as I can tell, I don't use this option.

Has anyone else experienced the mysterious NPEs using android and proguard. Are there other settings that people can recommend for a set of optimizations that can cause this problem?

Any other ideas?

For reference, here is an unobservable function that gets NPE:

public MainMenuScreen(final HauntedCarnival game) { super(game); game.startMusic("data/music/intro.mp3"); stage = new Stage(Screen.SCREEN_WIDTH, Screen.SCREEN_HEIGHT,true); stage.addActor(new Image("background", Assets.mainMenuBackground)); Image title = new Image("title", Assets.mainMenuTitle); title.x = 0; title.y = 340; resetEyeBlink(); stage.addActor(title); dispatcher.registerInputProcessor(stage); settings = game.getSettings(); eyeBlinkImage = new Image("eyeBlink", Assets.eyeBlink); if (settings.getPlayers().isEmpty()) { settings.addPlayer("Player One"); settings.save(game); } setupContinue(); } 

So the only features that I see are the game, the dispatcher, and the settings.

the game is installed through this code in another class. the game is the final variable in this other class:

 game.setScreen(new MainMenuScreen(game)); 

the dispatcher gets installed inside when calling super above.

getSettings () returns the settings object, which is installed at the very beginning of the application, is closed and never canceled. It has also been used several times before this method.

There are no primitives for automatic boxing.

here is the proguard configuration:

 -optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -keepattributes Signature -keep public class com.alkilabs.hauntedcarnival.settings.Settings -keep public class com.alkilabs.hauntedcarnival.settings.Settings { *; } -keep public class com.alkilabs.hauntedcarnival.settings.Player -keep public class com.alkilabs.hauntedcarnival.settings.Player { *; } -keepnames public class com.alkilabs.hauntedcarnival.world.World -keepnames public class * extends com.alkilabs.hauntedcarnival.world.upgrades.Upgrade -keepnames public class * extends com.alkilabs.hauntedcarnival.world.achievments.Achievement -keepnames public class com.alkilabs.hauntedcarnival.world.monsters.MonsterType -keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.monsters.Monster { public <init>(com.alkilabs.hauntedcarnival.world.monsters.MonsterType, java.lang.Integer, com.alkilabs.hauntedcarnival.world.World); } -keepnames public class com.alkilabs.hauntedcarnival.world.items.ItemType -keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.items.Item { public <init>(com.alkilabs.hauntedcarnival.world.World, java.lang.Integer, java.lang.Integer); } -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -dontwarn com.badlogic.gdx.scenes.scene2d.ui.utils.DesktopClipboard -dontwarn com.badlogic.gdx.utils.JsonWriter -dontwarn com.badlogic.gdx.utils.XmlWriter -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } 
+6
source share
3 answers

Ok, I think I got to the root of the problem / confusion.

One of the things proguard does is inline methods. Because of this, the entire contents of my setupContinue () function at the bottom of my constructor was added directly to the contents of my constructor. So now I have even more code to review, and I see some additional features for NPE. I am sure that I will get to the bottom of my problem.

I figured this out by taking obfuscated.jar, which produces proguard, and running it through a decompiler. Its an interesting exercise as you get a little more information about the internal workings of proguard. I highly recommend it to people who want to better understand the consequences that the protector has on their code.

+8
source

It is best to use the mapping.txt file and the retrace tool to find the exact location of the error. From there, it would be easier to understand if this is really a Proguard or some other end that you haven't thought about.

To do this, you need to copy the stack trace from the developer console to another file, suppose it is called

C: \ trace.txt

Now in your project you will find the Proguard folder with 4 files. Suppose your project is in

C: \ project

What you need to do is run the retrace tool (using the batch file for easier use) located in (changing the location of your Android Sdk folder):

C: \ Android, SDK windows \ tools \ ProGuard \ Bin \ retrace.bat

Go to this folder and run:

retrace c: \ project \ proguard \ mapping.txt c: \ trace.txt

From there it would be much easier to determine our exact exception string and probably find an error.

In my experience, the only things that can be confused are third-party libraries. The usual Android code for all my projects has never been affected by obfuscation.

+2
source

Sorry that I can not leave comments (I'm new to SO).

This may be another issue that I am facing. On some phones, at some point, a problem arose with missing Android libraries, such as the JSon library.

I would recommend you study more closely which phones actually receive NPE - maybe there are some similarities.

In my case, this is HTC Desire Z, which lacked the JSon library, and therefore the application was closed every time a part of JSon was called. The problem was fixed by HTC later with a fix for Desire Z rom.

+1
source

Source: https://habr.com/ru/post/898490/


All Articles