25

EDIT: Before down-voting and implying things, please understand I cannot reproduce this error. This happens constantly on certain devices which I do not have access to, but not after a firmware reset!

I recently discovered random crashes in an app I am developing for a customer. The app has roughly 100.000 active users now after 3 years.

We've seen the crash on Nexus 4 and 5, both with Android 4.4 KitKat.

We cannot reproduce it on our own Nexus 4 and 5 running 4.4.

We've had a customer through our support. He told us the crash happens every time at the same place when invoking a new activity. He was running Dalvik, not ART. After resetting the firmware the app worked fine and could not reproduce it again!

I cannot post the source or layout for legal reasons, but have this stacktrace:

java.lang.RuntimeException: Unable to start activity ComponentInfo{xx.xxx.xxxxx.xxx.xxxxxx.prod/xx.xxx.xxxxx.xxx.PaymentsActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)
at android.app.ActivityThread.access$700(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4998)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:126)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:4938)
at android.view.View.sendAccessibilityEventUnchecked(View.java:4919)
at android.view.View$SendViewStateChangedAccessibilityEvent.run(View.java:19433)
at android.view.View$SendViewStateChangedAccessibilityEvent.runOrPost(View.java:19465)
at android.view.View.notifyViewAccessibilityStateChangedIfNeeded(View.java:7265)
at android.view.View.setFlags(View.java:8990)
at android.view.View.setVisibility(View.java:6020)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:859)
at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)
at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:547)
at android.view.LayoutInflater.parseInclude(Native Method)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:745)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)
at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:547)
at android.view.LayoutInflater.inflate(Native Method)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1928)
at xx.xxx.xxxxx.xxx.StandardActivity.setContentView(StandardActivity.java:289)
at xx.xxx.xxxxx.xxx.PaymentsActivity.onCreate(PaymentsActivity.java:61)
at android.app.Activity.performCreate(Activity.java:5243)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
... 12 more

EDIT: Second stacktrace without xposed

java.lang.RuntimeException: Unable to start activity ComponentInfo{xx.xxx.xxxxx.xxx.xxxxx.prod/xx.xxx.xxxxx.xxx.PaymentsActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)
at android.app.ActivityThread.access$700(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4998)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:4938)
at android.view.View.sendAccessibilityEventUnchecked(View.java:4919)
at android.view.View$SendViewStateChangedAccessibilityEvent.run(View.java:19433)
at android.view.View$SendViewStateChangedAccessibilityEvent.runOrPost(View.java:19465)
at android.view.View.notifyViewAccessibilityStateChangedIfNeeded(View.java:7265)
at android.view.View.setFlags(View.java:8990)
at android.view.View.setVisibility(View.java:6020)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:859)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:745)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1928)
at xx.xxx.xxxxx.xxx.StandardActivity.setContentView(StandardActivity.java:289)
at xx.xxx.xxxxx.xxx.PaymentsActivity.onCreate(PaymentsActivity.java:61)
at android.app.Activity.performCreate(Activity.java:5243)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
... 11 more

The layout being set in setContentView() contains frames, else it's pretty standard and plain.

Any input is highly appreciated :-)

Jens Vesti
  • 375
  • 3
  • 11
  • 2
    The problem can be in the layout, maybe [this](http://developer.android.com/about/versions/android-4.4.html) page can help you. Check if something you used is changed in 4.4.. without code is a bit hard. – Marco Acierno Dec 06 '13 at 17:10
  • 1
    A NPE shouldn't be hard to find and solve – Robin Dijkhof Dec 06 '13 at 17:14
  • 2
    An NPE in framework code like this can be harder to find and solve, since you don't have direct control over that code. Although you can grab the source from AOSP so you can trace the code flow and get a better understanding of why the NPE might be happening. – JesusFreke Dec 06 '13 at 20:34
  • Also, I'm not sure why the downvotes on this question. It seems like a perfectly legitimate question to me. – JesusFreke Dec 06 '13 at 20:36
  • The "de.robv.android.xposed.XposedBridge.main(XposedBridge.java:126)" entry in the stack trace looks somewhat suspicious. xposed is a framework for hooking and potentially modifying the behavior of classes. (http://repo.xposed.info/module/de.robv.android.xposed.installer) – JesusFreke Dec 06 '13 at 20:49
  • Not sure why this was down-voted. Let me clarify, I _cannot_ reproduce the error @Robin Dijkhof. The NPE is deep in the Android framework. – Jens Vesti Dec 06 '13 at 21:05
  • I highly suspect this might be related to the reporters use of the xposed framework. – JesusFreke Dec 06 '13 at 21:09
  • I don't use xposed, @JesusFreke - The Android framework does. Everything above 'at android.app.Activity.setContentView(Activity.java:1928)' is out of my control. – Jens Vesti Dec 06 '13 at 21:11
  • @JensVesti I think their talking about the **person who reported the issue**, not your app. – hichris123 Dec 06 '13 at 21:24
  • Correct. It looks like the person who reported the bug is using the xposed framework for some reason, and its entirely possible it could be doing something that eventually leads to the crash that was reported. In other words, it may not be a bug in your application at all. – JesusFreke Dec 06 '13 at 21:28
  • Ah, thanks @hichris123 :) I'll update with another stack trace which does not contain xposed. – Jens Vesti Dec 06 '13 at 21:29
  • 1
    Ah, ok. If you've seen the bug elsewhere (i.e. with no xposed entries in the stack trace) then that's unlikely to be the problem. In that case, I recommend grabbing the AOSP source and looking at the location mentioned in the stack trace. You can work backwards from there, trying to determine what conditions would cause an NPE at that point. – JesusFreke Dec 06 '13 at 21:31
  • That's a good idea, @JesusFreke! And thanks for the link, @Marco Lopez Acierno - I should actually check the compiler actually compiling the code. It's a buildserver I don't have control over, which may not be running the latest compiler. – Jens Vesti Dec 06 '13 at 21:35

2 Answers2

12

I've also run into this same problem with some code I was maintaining. I was able to consistently replicate the bug by enabling TalkBack in the accessibility options.

First, here's the method from View.java where the null reference that caused the crash was used, from the KitKat release of Android:

void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
    if (!isShown()) {
        return;
    }
    onInitializeAccessibilityEvent(event);
    // Only a subset of accessibility events populates text content.
    if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) {
        dispatchPopulateAccessibilityEvent(event);
    }
    // In the beginning we called #isShown(), so we know that getParent() is not null.
    getParent().requestSendAccessibilityEvent(this, event);
}

For me, the root cause turned out to be a custom View which had overridden View.isShown() like so:

public boolean isShown(){
  return someCondition;
}

This meant that sendAccessibilityEventUncheckedInternal would run past the if(!isShown()) check that it makes before proceeding even when the View had a null parent, and so caused the crash.

I had originally thought it was a concurrency problem, because I assumed the isShown() check had ensured the parent wasn't null and that the reference to the View's parent had been changed during the execution of sendAccessibilityEventUncheckedInternal. Wrong!

If you find a similar problem, especially in code you didn't write, you can prevent this crash pretty easily by including the result of the superclass's isShown() (assuming you are changing code in a direct subClass of View):

public boolean isShown(){
  return super.isShown() && someCondition;
}
Captain Blammo
  • 1,897
  • 20
  • 31
  • 2
    You rock, @Captain Blammo! There actually was an override of isShown() I still cannot reproduce it, but will apply the fix you suggested to see if it fixes it :-) – Jens Vesti Jan 10 '14 at 09:25
  • This solved a similar issue as I've too created a custom `View` and have overridden the `isShown()`-method. – deubaka Mar 25 '14 at 09:01
  • This response has saved me... apparently I had the same problem. My app worked perfectly on a Samsung device and crashed on a LGG3 device! This fix, however, solved my problem. Thanks! – Cookienator Oct 22 '15 at 13:49
  • Done! I never heard or saw anything related this problem again, so it must have worked :) – Jens Vesti Nov 12 '15 at 08:53
  • Thanks dude. Happy coding! – Captain Blammo Nov 12 '15 at 16:35
2

My users have been running into the same problem and it appears to be caused by one or more accessibility options being turned on. Some of my users were using the Pebble smart watch which installs an accessibility option - so it's not just TalkBack, etc.

The diagnosis

Take a look at this bit of KitKat's View#setFlags() method at https://github.com/android/platform_frameworks_base/blob/kitkat-mr1-release/core/java/android/view/View.java#L9006

if (accessibilityEnabled) {
  ...
  notifyViewAccessibilityStateChangedIfNeeded(
                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}

that sends you down the rabbit hole ending in a NullPointerException if it's executed before the View is attached to the view hierarchy (i.e. is has no parent) because in View#sendAccessibilityEventUncheckedInternal() at https://github.com/android/platform_frameworks_base/blob/kitkat-mr1-release/core/java/android/view/View.java#L4952 we have:

getParent().requestSendAccessibilityEvent(this, event);

My workaround (which looks like it won't work for you)

For my app, I am creating a View subclass programmatically and was calling View#setOnClickListener() in the constructor. Instead, I now call View#setOnClickListener() from

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    /* Due to a bug in how Android 4.4 handles accessibility options,
     * we can't set the onClick listener until this View has a parent or we will
     * get an NPE. */
    setOnClickListener(this);
}

It works because this View will have a parent by the time View#onAttachedToWindow() gets called.

Your stack trace is more problematic though. You're falling into the rabbit hole via attributes on an XML layout. I haven't come up with an idea for you. One thought is that this must only happen at app startup - otherwise virtually all inflations of XML layouts would trigger the crash because there are so many paths that take you through View#setFlags(). In my app, this one spot appears to be the only crash and it happens at app startup. It's not a pleasant idea but one possibility is to re-order things to inflate this view later.

bpenrod
  • 176
  • 1
  • 3
  • 1
    Brilliant, @bpenrod ! I'm guessing it's a concurrency problem as well: `void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { if (!isShown()) { //<-- parent is not null return; } ... // In the beginning we called #isShown(), so we know that getParent() is not null. getParent().requestSendAccessibilityEvent(this, event); //<-- parent is now null, same thread :-| }` (EDIT: ^I have no idea how to format that code properly) Or someone in the call path has set it to null. I need to dig some more. – Jens Vesti Dec 18 '13 at 13:03
  • [Method added in comment above](https://github.com/android/platform_frameworks_base/blob/kitkat-mr1-release/core/java/android/view/View.java#L4942) – Jens Vesti Dec 18 '13 at 13:09