Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android LicenseChecker crashes with null pointer exception

Tags:

android

crash

It seems that if an Android phone is not logged in to Google Play, a checkAccess-call will throw a NullPointerException and eventually crash the application:

// user not logged in to Google Play
LicenseChecker licenseChecker = new LicenseChecker(...);
licenseChecker.checkAccess(...) // throws a nullpointer exception and crasches the app

The NullPointerException happens deep inside the Android framework in a separate thread:

FATAL EXCEPTION: background thread
java.lang.NullPointerException
com.google.android.vending.licensing.LicenseValidator.verify()

hence there seems no way for the application to catch it and avoid the crash.

Any ideas how to avoid this crash? (t should be a legal situation not to be logged into Google Play)

The only way I can think of is to check Google Play login status prior to invoking checkAccess.

like image 485
Jakob Bjerre Jensen Avatar asked Jul 03 '13 16:07

Jakob Bjerre Jensen


3 Answers

If you are simply trying to run your code on an android emulator, you can alternatively open and sign into the Google Play Store, which will update Google Play Services and fix the problem

like image 86
Jared Avatar answered Oct 23 '22 09:10

Jared


I'm downvoting @Ben Lee's answer.

Building upon the recommendation that @jssingh made above, I went with the following solution:

public void verify(PublicKey publicKey, int responseCode, String signedData, String signature) {
    String userId = null;
    // Skip signature check for unsuccessful requests
    ResponseData data = null;
    if (signedData != null && (responseCode == LICENSED || responseCode == NOT_LICENSED ||
            responseCode == LICENSED_OLD_KEY)) {
        // Verify signature.
        try {
            Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
            sig.initVerify(publicKey);
            sig.update(signedData.getBytes());
        ....
        }
    }

    ........

    if (signedData == null) {
        Crashlytics.logException(new Exception("Licensing signedData is null - responseCode=" + responseCode));
    }

    switch (responseCode) {
        case LICENSED:
        case LICENSED_OLD_KEY:
            int limiterResponse = mDeviceLimiter.isDeviceAllowed(userId);
            handleResponse(limiterResponse, data);
            break;
        .....
    }

I leveraged Crashlytics logging to validate the claim that you CANNOT just assume NOT_LICENSED when signedData is null.

As a matter of fact, this is the condition I see my code taking with this additional check in place:

        case ERROR_CONTACTING_SERVER:
            Log.w(TAG, "Error contacting licensing server.");
            handleResponse(Policy.RETRY, data);
            break;

Seems legit :)

like image 21
ShellDude Avatar answered Oct 23 '22 10:10

ShellDude


I modified the method LicenseValidator.verify(), adding a protection check at the begining:

public void verify(PublicKey publicKey, int responseCode, String signedData, String signature) {
    if (signedData==null){
        handleInvalidResponse();
        return;
    }
    ...
}
like image 9
Ben Lee Avatar answered Oct 23 '22 08:10

Ben Lee