Search code examples
androidandroid-intentsegmentation-faultillegalargumentexceptionsigbus

After running startActivity for 2nd time in Service, my app starts crashing with Exceptions, Sigbus or Sigsegv errors


I'm developing an app and have a really big problem understanding or finding the cause of the errors I'm getting. Full code is available on Github: https://github.com/lordgreg/Sfen. The problematic line is ALWAYS startActivity(intent) around line 608 (https://github.com/lordgreg/Sfen/blob/master/app/src/main/java/gpapez/sfen/BackgroundService.java)

Here's how I reproduce the error:

  • create new profile, which can have an "action" which creates new Shortcut (widget)- it actually saves Intent as Gson string (I've had to use (de)serialization because of Uri).
  • i can run this profile (clicking on it just runs all actions) as many times as i want and the intent will run without any problem.
  • now, there are "events" which trigger on special conditions and don't do anything else except run specific profile (the same as clicking on profile again). this works. event's conditions are met, i send broadcast EVENT_ENABLED, Receiver gets it, it start our function which triggers profile, run actions and sendActivity works with intent that it got from Gson. its perfect.
  • the problem comes, when i close the app down and reopen it.
  • then, a Receiver sends me a signal to rerun event (which worked when I clicked it AND works if i manually click the profile).

Here Is One Example of error:

08-04 21:27:50.065  21621-21621/gpapez.sfen E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: gpapez.sfen, PID: 21621
    java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.STATE_CHANGE flg=0x4000010 (has extras) } in gpapez.sfen.Receiver@44b7a678
            at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:791)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5151)
            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:878)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
            at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalArgumentException
            at android.os.Parcel.nativeAppendFrom(Native Method)
            at android.os.Parcel.appendFrom(Parcel.java:436)
            at android.os.Bundle.writeToParcel(Bundle.java:1679)
            at android.os.Parcel.writeBundle(Parcel.java:641)
            at android.content.Intent.writeToParcel(Intent.java:7026)
            at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2084)
            at android.app.Instrumentation.execStartActivity(Instrumentation.java:1419)
            at android.app.ContextImpl.startActivity(ContextImpl.java:1079)
            at android.app.ContextImpl.startActivity(ContextImpl.java:1061)
            at android.content.ContextWrapper.startActivity(ContextWrapper.java:311)
            at gpapez.sfen.BackgroundService.runProfileActions(BackgroundService.java:647)
            at gpapez.sfen.BackgroundService.runEventActions(BackgroundService.java:749)
            at gpapez.sfen.BackgroundService.EventFinder(BackgroundService.java:346)
            at gpapez.sfen.Receiver.onReceive(Receiver.java:189)
            at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:781)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5151)
            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:878)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
            at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
            at dalvik.system.NativeStart.main(Native Method)

Or another:

08-04 21:38:30.950  22971-22971/gpapez.sfen E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: gpapez.sfen, PID: 22971
    java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.STATE_CHANGE flg=0x4000010 (has extras) } in gpapez.sfen.Receiver@451087f0
            at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:791)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5151)
            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:878)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
            at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalArgumentException
            at android.os.Parcel.nativeAppendFrom(Native Method)
            at android.os.Parcel.appendFrom(Parcel.java:436)
            at android.os.Bundle.writeToParcel(Bundle.java:1679)
            at android.os.Parcel.writeBundle(Parcel.java:641)
            at android.content.Intent.writeToParcel(Intent.java:7026)
            at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2084)
            at android.app.Instrumentation.execStartActivity(Instrumentation.java:1419)
            at android.app.ContextImpl.startActivity(ContextImpl.java:1079)
            at android.app.ContextImpl.startActivity(ContextImpl.java:1061)
            at android.content.ContextWrapper.startActivity(ContextWrapper.java:311)
            at gpapez.sfen.BackgroundService.runProfileActions(BackgroundService.java:647)
            at gpapez.sfen.BackgroundService.runEventActions(BackgroundService.java:749)
            at gpapez.sfen.BackgroundService.EventFinder(BackgroundService.java:346)
            at gpapez.sfen.Receiver.onReceive(Receiver.java:189)
            at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:781)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5151)
            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:878)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
            at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
            at dalvik.system.NativeStart.main(Native Method)

When this happens, my app becomes unusable, I have to go into system settings and clear data for the app itself. After that, I can rerun, create profile again, create event which shows profile and i can trigger my shortcut actions which just run this code:

            /**
             * get Intent from saved setting
             *
             * http://stackoverflow.com/questions/22533432/create-object-from-gson-string-doesnt-work
             */
            class UriDeserializer implements JsonDeserializer<Uri> {
                @Override
                public Uri deserialize(final JsonElement src, final Type srcType,
                                       final JsonDeserializationContext context) throws JsonParseException {
                    return Uri.parse(src.getAsString());
                }
            }

            Gson gsonIntent = new GsonBuilder()
                    .registerTypeAdapter(Uri.class, new UriDeserializer())
                    .create();

            Intent intent = gsonIntent.fromJson(act.getSetting("shortcut_intent"), Intent.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            System.out.println("*** Opening intent\n" + act.getSetting("shortcut_intent"));

            startActivity(intent);

The line for which errors show

 at gpapez.sfen.BackgroundService.runProfileActions(BackgroundService.java:647)

is exactly:

startActivity(intent);

If I then try to reopen app, I always get Exception above. Now here is the twist... waiting a while after crash (+1min) reopens app without a problem and I can continue opening everything until next crashes.

Please help me out on why is this happening... I'm even willing to pay to the person that finds out and solves the mistery (Illegal Argument Exception and Error Receiving Broadcast Intent that both lead to line startActivity(intent))! Its the only thing with which I could express my gratitude on helping me out!

Thank you!


Solution

  • I will answer my own question since I've managed to finally find a reason for crashing.

    1. As explained, when saving Profile action, in our case Shortcut, I've had to save Shortcut Intent. Since Gson complained about Uri (java.lang.RuntimeException: Failed to invoke private android.net.Uri() with no args), you have to create your own Serializer and Deserializer classes and pass those to Gson object.

    After that, you can finally save Intent object to String using Gson. It would look something like this:

    {
        "mAction": "android.intent.action.VIEW",
        "mData": "http://www.amazon.com/",
        "mExtras": {
            "mParcelledData": {
                "mOwnsNativeParcelObject": true,
                "mNativePtr": -1197637952
            },
            "mHasFds": false,
            "mFdsKnown": true,
            "mAllowFds": true
        },
        "mFlags": 0
    }
    

    And after you need the string converted Intent, you would call it like:

    Intent intent = new Gson().fromJson(act.getSetting(MY_INTENT_STRING, Intent.class);
    

    Since this didn't caused any problems, Intent was created, everything better than expected, BUT, after 2 days of setting breakpoints and checking code line by line, here is actual fromGson() string we get:

    {
        "mAction": "android.intent.action.VIEW",
        "mData": "http://www.amazon.com/",
        "mExtras": {
            "mMap": {
                "com.android.browser.application_id": "-2531992419148236456"
            },
            "mHasFds": false,
            "mFdsKnown": true,
            "mAllowFds": true
        },
        "mFlags": 0
    }
    

    As you see, even if we implemented Serializer and Deserializer, some differences occur.

    Suggestion?

    NEVER USE GSON TO SAVE INTENT. No matter the intent, you can store it to string and receive it out nicely with:

    // like this to save intent
    String mySavedIntent = intent.toUri(Intent.URI_INTENT_SCHEME)
    

    and

    // like this to retrieve intent from string
    intent = Intent.parseUri(mySavedIntent, Intent.URI_INTENT_SCHEME)