javaandroidironsource

NullPointerException on primitive boolean property


I am trying to fix a bug that crash an app that I published to the Google Play store.

The crash stack trace from the Google Play console:

java.lang.NullPointerException: 
  at com.myApp.Advertising.InterstitialAdsRunCallback.setViewed (InterstitialAdsRunCallback.java:11)
  at com.myApp.AndroidLauncher$2.onInterstitialAdClosed (AndroidLauncher.java:65)
  at com.ironsource.mediationsdk.A$4.run (A.java:7)
  at android.os.Handler.handleCallback (Handler.java:938)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loop (Looper.java:223)
  at android.app.ActivityThread.main (ActivityThread.java:7888)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:981)

The code for the setViewed function is:

package com.myApp.Advertising;

public abstract class InterstitialAdsRunCallback implements Runnable {
    boolean viewed;

    public boolean viewedAd() {
        return viewed;
    }

    public void setViewed(boolean viewed) {
        this.viewed = viewed; // line 11
    }
}

And the code that is calling setViewed:

public void onInterstitialAdClosed() {
    InterstitialAdsRunCallback adRunnable = showInterstitialAdRunnable.getAdRunnable();
    adRunnable.setViewed(true); // line 65
    adRunnable.run();
    IronSource.loadInterstitial();
}

Decompiled InterstitialAdsRunCallback class from the .aab:

.class public abstract Lcom/myApp/Advertising/InterstitialAdsRunCallback;
.super Ljava/lang/Object;
.source "InterstitialAdsRunCallback.java"

# interfaces
.implements Ljava/lang/Runnable;


# instance fields
.field public viewed:Z


# direct methods
.method public constructor <init>()V
    .registers 1

    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

So, how is a primitive boolean property causing a NullPointerException? I'm probably missing something else.


Solution

  • R8, ProGuard and other similar optimization tools usually inline accessor methods but the line number information still points to the original source.

    If adRunnable is null and the setViewed() accessor is inlined, you'll get an NPE like this.