How to find source of crashes of type java.lang.RuntimeException: Parcel android.os.Parcel@####: Unmarshalling unknown type code XXXX at offset YYY

若如初见. 提交于 2020-01-02 02:46:07

问题


Our crash reporting system is logging crashes of this type:

Caused by java.lang.RuntimeException: Parcel android.os.Parcel@8bf0d1f: Unmarshalling unknown type code 6881391 at offset 356
   at android.os.Parcel.readValue(Parcel.java:2779)
   at android.os.Parcel.readSparseArrayInternal(Parcel.java:3148)
   at android.os.Parcel.readSparseArray(Parcel.java:2362)
   at android.os.Parcel.readValue(Parcel.java:2757)
   at android.os.Parcel.readArrayMapInternal(Parcel.java:3067)
   at android.os.BaseBundle.unparcel(BaseBundle.java:257)
   at android.os.Bundle.getSparseParcelableArray(Bundle.java:958)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1329)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:3194)
   at android.support.v4.app.Fragment.restoreChildFragmentState(Fragment.java:1444)
   at android.support.v4.app.Fragment.onCreate(Fragment.java:1415)
   at com.payments.base.BaseFragment.onCreate(BaseFragment.java:68)
   at com.payments.app.fragments.TopLevelFragment.onCreate(TopLevelFragment.java:422)
   at android.support.v4.app.Fragment.performCreate(Fragment.java:2331)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1386)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:3194)
   at android.support.v4.app.Fragment.restoreChildFragmentState(Fragment.java:1444)
   at android.support.v4.app.Fragment.onCreate(Fragment.java:1415)

What I know: This occurs when app is restored from background, and onCreate is called. Our app is a Single-Activity app, with all UI managed by fragments. This crash is infrequent, and very hard to reproduced in our dev environment.

Also - I don't believe the cause is some parcelable object we created, rather Android component reloading, but not sure.

What I'd like to know: how to analyze these stacktraces to pinpoint the cause? how to make use of the little data given?

Note that the stacktrace hardly points to any particular line in our app, and where it does - only to the onCreate methods of our activity and fragments base classes


回答1:


I just learned that you can keep your test device from keeping activities. There is an option in the Developer options, section "Apps" that, when switched on, destroys activities everytime they user leaves them.

After turning this option on, I was able to reproduce the error by just closing and reopening my app. As you said, it's an error in the onCreate() method. In my case, the reason is a ClassNotFoundException when unmarshalling a custom Parcelable from my saved instance state. This might not be a solution to your problem but at least might help you to reproduce and pin down the error. Happy hunting!




回答2:


In my experience, an error such as this is less about what is happening when the error occurs, and more about what happened earlier in your app. Specifically when the app went into the background.

But starting with what the stack trace is revealing. TopLevelFragment is being restored from previous state. During this restore, TopLevelFragment's child fragments are being restored. While restoring the child fragments, the saved fragment state of one of the fragment's attempts to unparcel itself when getSparseParcelableArray() is called on Bundle to retrieve the fragment's saved view state. This happens in FragmentManager.java, line 1329. There's something about the saved fragment state that Parcel doesn't know what to do with as it's unmarshaling itself.

To narrow down which child fragment of TopLevelFragment you should focus on, I would put a breakpoint on line 1329 of FragmentManager.java and inspect the type Fragment f is. Keep in mind, you may have multiple child fragments getting restored, so you want to see which fragment can't get past line 1329.

But of course you have force this restore logic to happen consistently. If you simply send your app to the background and bring it back to the foreground, this probably won't happen. So you can do as Richard R suggests and use the "Don't keep activities" developer option to force Android to destroy and restore activities.

Once you narrow down which fragment is the problem, you need to go back earlier in your app and take a closer look at the types of data you are putting into the save state in Fragment.onSaveInstanceState(). Hopefully this points you in the right direction.

If this is a proguard problem, you should see the error disappear if you disable minification. And if that's the case, you may need a proguard rule or a @Keep annotation on one of your custom Parcelable types. If the error happens with and without minification, it's probably not proguard related.




回答3:


Getting this type of stack traces we can user crashlytics or we can set manually default exception handler

    public class BaseActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
    String path = Environment.getExternalStorageDirectory()
    + "/" + getString(R.string.app_name);
    Thread.setDefaultUncaughtExceptionHandler(new
    CustomExceptionHandler(path, ""));
    }
    }

For storing log into file path...

public class CustomExceptionHandler implements       UncaughtExceptionHandler {
private UncaughtExceptionHandler defaultUEH;
private String dirName;
private String url;

/*
* if any of the parameters is null, the respective functionality
* will not be used
*/           
public CustomExceptionHandler(String dirName, String url) {
this.dirName = dirName;
this.url = url;
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}

public void uncaughtException(Thread t, Throwable e) {
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
String stacktrace = result.toString();
printWriter.close();           
if (dirName != null) {
writeToFile(stacktrace);
}
defaultUEH.uncaughtException(t, e);
}          
private void writeToFile(String stacktrace) {
try {
File myDir = new File(dirName.replace(" ", "") + "_Log");
if (!myDir.exists()) {
myDir.mkdir();
}
//Store only 10 file in device because of size.
if (myDir != null & myDir.isDirectory() & myDir.listFiles().length > 10) {
File[] filelist = myDir.listFiles();
for (int i = 0; i < filelist.length; i++) {
try {
filelist[i].delete();
} catch (Exception e) {}
}
}
Calendar c = Calendar.getInstance();                       c.setTimeInMillis(System.currentTimeMillis());
String fileName = "";
fileName = c.get(Calendar.SECOND) + "-" +
c.get(Calendar.MINUTE) + "-" +
c.get(Calendar.HOUR) + "-" +
(c.get(Calendar.AM) == 0 ? "AM" : "PM") + "_" +
c.get(Calendar.DAY_OF_MONTH) + "-" +
(c.get(Calendar.MONTH) + 1) + "-" +
c.get(Calendar.YEAR) + ".txt";
File f = new File(myDir, fileName);
FileWriter fr = new FileWriter(f);
BufferedWriter bos = new BufferedWriter(fr);
bos.write(stacktrace);
bos.flush();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}


来源:https://stackoverflow.com/questions/55159506/how-to-find-source-of-crashes-of-type-java-lang-runtimeexception-parcel-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!