preface

Any Transform byte is dangerous, so if you really think you can’t solve all the oddities on the line, you should be careful with this technique. Shrimp from a very special dish.

If you’re unlucky enough to click on this post because of this bug, I’d like to say that you are out of luck, so let’s give a round of applause to the victim.

First of all, I personally feel that this problem is very difficult to troubleshoot and locate, just from the stack log, you can be confused.

VerifyError troubleshooting

Let’s first look at the definition of this exception.

Java.lang.VerifyError means that the JVM verifies the correctness of a class when loading it. This Error is reported only when the class file is invalid.

This problem occurs during the life cycle of a class. In general, this is very similar to an article I wrote a year ago exploring this issue with ClassNotFoundException | class loading mechanism. This is also a question before COMING to B and the byte big guy interview discussion, now look back, in fact, benefit a lot, also probably know how to check and debug this kind of problem.

The essence of the problem is the aforementioned androidx upgrade. Upgrading the fragment version to 1.4.3 added an argument constructor to the base fragment construct, which later led to this strange problem.

While graying online, we noticed a strange crash exception on a 4.4 device. The devices on other systems are fine. Later, we found a 4.4 device and found that this problem did occur in the release version. The abnormal situation is shown below.

FATAL EXCEPTION: main
at java.lang.VerifyError: androidx/fragment/app/DialogFragment
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2949)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1971)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:311)
at androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:249)
at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244)
at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669)
at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631)
at androidx.viewpager.widget.ViewPager.dataSetChanged(ViewPager.java:1086)
at androidx.viewpager.widget.ViewPager$PagerObserver.onChanged(ViewPager.java:3097)
at androidx.viewpager.widget.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:291)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5162)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(NativeStart.java)
Copy the code

The phenomenon is very simple, this time all our dialogfragment actually hung, on the 4.4 device, as long as there is this structure will cause this abnormal crash.

At first we just thought it was confusion that caused the exception, but after trying to keep all androidX classes, I found that the problem was still stable and I was a little confused.

After a simple analysis of exceptions, it was speculated that there was a problem with the dialogfragment class itself, so the bytecode security verification failed when the class was loaded. But this part is androidX internal code ah, it is not not talking about martial morality?

When you hit a dead end, you can still try to ask your colleagues around you, also can be your boss, is the so-called one-man plan short. Sometimes it does work wonders. It’s an old driver’s theory.

My boss did deal with this problem before, but the part he dealt with before was that all models must fail, and it was related to confusion. The dalviKVM will print the error message when checking the code. That happens to correspond to the classNotFound exception.

06-15 18:11:16. 876, 13235-13235 /? W/ dalviKVM: VFY: invoke-direct <init> must be on current class or super 06-15 18:11:16.876 13235-13235/? W/ DALviKVM: VFY: Reality OPcode 0x70 at 0x0000 06-15 18:11:16.876 13235-13235/? W/dalvikvm: VFY: rejected Landroidx/fragment/app/DialogFragment; .<init> (I)VCopy the code

The constructor calls the current class, not the parent class. So this part of the bytecode is an exception.

In this part, our company has made a part of bytecode parent class replacement, so DialogFragment has actually been modified. In the new version of androidx, you add another constructor to the Fragment with arguments, so this part of the Fragment gets an exception.

In fact, the follow-up work was relatively good after the problem was identified, while the reconstruction was completed by another leader. If you are interested, you can refer to the Lancet written by the leader before. The functions are similar, and I may have to go to the HR office to get the resignation certificate if I mentioned the details.

View Apk bytecode by AS

Another big guy incidentally taught me how to view the bytecode of the final product from APK. A quick way to view class bytecode without decompiling the entire APK with JADX.

Use this section to quickly view the exceptions in the same way as the screenshot BELOW.

  1. Drag into Android Studio and click ON APK

  1. To find the class you want to see, right-click Show Bytecode

  1. Take a look at

This section is an exception reference

Android don’t want to talk to you, throw a Java. Lang. This is from another VerifyError bi li bi li AnZhuoJu guy.

Since the problem was triggered on a lower-version phone, the Dalvik VM was still running, and it was easy (Google) to find the dexverify.cpp and CodeVerify.cpp classes in the source code for the corresponding version (4.1.1)

(dvmVerifyClass() is a good place to start reading about class checking.)

VerifyMethod () in DexVerify eventually calls CodeVerify’s dvmVerifyCodeFlow() to ensure that the individual method execution flow in the class is legitimate.

Notice that Exception Hanler was also being validated at this time, and its opcode was OP_MOVE_EXCEPTION (0x0D, which was mentioned in the earlier log ‘Opcode 0x0D’).

The check method getCaughtExceptionType() will report an error if the exception class specified in the catch block (such as ErrnoException in the example) is not found: “VFY: unable to resolve exception class 1594 (Landroid/system/ErrnoException;) “, after trying various possibilities and still not knowing how to handle the exception, the code is thought to have a problem and the logs report errors: “VFY: Unable to find exception handler at ADDR 0xe” and “VFY: unable to find exception handler at ADDR 0xe” rejected Lcom/sample/FileUtils; .getUid (Ljava/lang/String;) I ‘

The dvmVerifyCodeFlow() method return false marked verifyMethod() failed, rejecting the reality of loading classes: “Verifier rejected class Lcom/sample/FileUtils;”

conclusion

Personally, I think, as a developer, communicating with others more is of great help to your technical improvement, problem solving, and many ideas related to it.

It doesn’t have to be something you don’t know at all. Maybe some ideas and ways to solve problems are worth learning. Besides, learning from other colleagues can also satisfy their desire to drink, and they will honestly not refuse you.

This article is relatively very short, but helpless with the author level is limited, can hit so many words, much have offended, you especially yao also can’t hit me !!!!

And three last words, counting this one, no.