Monday, January 29, 2007

Verification Errors With Blackberry Applications

If you've worked on applications for the Blackberry and you're unlucky (like me), you may have tried to run your application on the simulator or a device and seen an error message something like this:

"Error starting MyApp: Module 'MyApp' has verification error 2778 at offset 3fce"

It appears that the two numbers (2778 and 3fce, in this case) are not helpful in diagnosing the problem. Basically, you're on your own. And it's going to get ugly.

According to RIM, it's likely that the COD files have been corrupted. Unfortunately, this can happen just by building with the rapc compiler, and optionally signing the app. So, what can you do? Well, I've fought with this a few times and I can at least give you some suggestions to try:

1) If you started by building a JAR and then used the rapc compiler to create COD files, make sure you turn obfuscation off when building the JAR. The rapc compiler will do its own obfuscating and it often has issues if the code is already obfuscated.

2) Comment out dead code. Sometimes the verification errors seem to have something to do with the size of the main code file and the library files. If you comment out some code that never gets called, the file sizes change somewhat, and this often fixes the problem.

3) Remove references to a static instance variable from an inner class. For example, code like the following can sometimes be a problem:

public class MyOuterClass {
static int var;

class MyInnerClass {
public void doSomething() {
var = 7;
}
}
}

There are a few ways you can try to remove these references. E.g., create get/set methods for var in the outer class, or modify your logic so you can pull MyInnerClass out of MyOuterClass.

4) Remove any System.out.* calls. These generally do nothing on the Blackberry, but sometimes cause verification errors.

5) Remove unused import statements.

6) Explicitly specify the access for every function or variable (i.e., make sure every one is specified as public, private, or protected). It's pretty easy to grep your Java code to find the missing access specifications.

Now, it's not clear to me whether these changes actually fix anything. However, you're really just stabbing in the dark with verification errors, so any changes you can think to make may help. My best advice is to use source control and build/test often. You're really just trying to avoid code that makes the compiler unhappy. And it's much easier to do this if 15 lines of code have been checked in since it last worked, as opposed to 1000.

17 comments:

Adam said...

I really want to thank you for posting this troubleshooting guide to an excessively frustrating error. I spent about a week tracking down and fixing the problem - and that was *with* source code control. Without SCC and your assistance, it could easily have taken a month.

For the record, and any other accursed souls who stumble into this wasps' nest of a problem, here was my offending code (not in an inner class or anything crazy like that):

public static String getUserName()
{
    if (username instanceof TextField)
    {
        return ((TextField) username).getText();
    }

    return UserInfo.getUserName();
}

Loda said...

Hi,

thanks for this post. this seem to be the only useful info I found.

in my case, to fix the problem, I did move back a static class with language const (ie: static string) from the project package to the lib package.

Also, the obfuscation of the midlet package (but not the Lib one) was a problem.

Loda

PS:
I'm using JDE 4.2.1 & Netbeans 6.1 to create a Midlet with a RIM signature and secure API.

Note that the "-defaultpackage ''" option for ProGuard did bring me other problem and I removed it.

Derek Phillips said...

Thanks for posting your solutions here! Would be great to compile a nice list of work-arounds for this issue. If anyone else has some success (or wants some other ideas to try) feel free to post them here.

Cliff said...

Hey Derek,

Did you try checking the version of rapc back when you encountered this problem? I've learned through a lot of heartache and pain that the version of rapc has an impact on whether or not your code runs. If you use 4.2.2, for eg. and deploy to 4.2.1 OS then you're asking for trouble. Also use only Blackberry tools for compiling. This includes Blackberry's preverify.exe, rapc.jar (or rapc.exe which just delegates to the jar), and the corresponding net_rim_api.jar. All of these tools should come from the correct JDE install for your target OS. That said, there's stil the possibility for random errors after you build. We're struggling ourselves to figure out the root cause of a current verification error. Chances are we won't find it.

Loda said...

Hi,

it's me again.

So, I found out that my methode of moving class from one package to an other does not fix the problem. It pretty much a random thing...

So, here is how I "fix" (hum...) the problem:

I use a made-by-hand .rapc files and re-compile the preverified source (so I can use defines) of ym netbreans project.

The mess was to create a batch which create the file list, import my lib and call the rapc. Then copy / move the files to the device/sim.

The important trick is that your .rapc must be in the root folder of your source tree. If not, the path for the ressource files (ie: images) is missing (use juste the filename).

Also, you may want to convert your .jar (lib) into .cod once-for-all. Then include them in the .jad/.alx.

I did not found a safe (meaning that will always work) way to convert a .jar to .cod

Hope its helps somebody...


PS:"the root cause of a current verification error" From my experience, such things does not exist. They are juste cause by a(some?) bug in the rapc, not by bad java code.

Loda said...

oups...

I mean "re-compile the preprocessed files" (the .java) and not "preverified".

Derek Phillips said...

Thanks for everyone's comments here. It's true that choosing the right version of rapc is quite important. Sometimes you just have to try 2 or 3 of them until one works.

Still, the most common issue I run into is accessing static members without prefixing them with the class name. It's easy to ensure this doesn't happen by enabling these settings under Properties -> Java Code Style -> Clean Up" in Eclipse:

Change non static accesses to static members using declaring type

Change indirect accesses to static members to direct accesses(accesses through subtypes)


Even if you're using the RIM JDE for building, it's easy to just open up the project in Eclipse and verify that your code conforms to this when problems arise.

Anonymous said...

When I had this problem, it seemed that I didn't have "public" as the scope modifier for my MIDlet class.
Once set the error went away.

YMMV
-Shawn

Luis Vivero said...

Hi,

Here is a way to identify the class and method which causes the ugly "verification error" using RIM's Java Device Simulator:

1. Open the emulator of the BlackBerry JDE
2. Load the application
3. Open the application
4. An error screen should appear stating something like this :

jvm error 104 uncaught runtime exception

5. Choose from the underlying menu (using the arrow keys) the option "catfail"

6. Now choose the right most point to save a file named "failure.zip" to your disk

7. Extract the files within failure.zip to your disk and open the .bug file

There are three interesting values in the .bug file:

VM:VECPs (the package)

VM:VECCs (the class)

VM:VECMm (the method which causes the error)

Hope this information could help you debugging this error, as it helps to me.

Luis

Vadim Berman said...

Another thanks for the useful tips, and possibly another tip from here (last message):

http://www.coderanch.com/t/230352/Java-Micro-Edition/Mobile/Verification-error-Blackberry

That was my problem. I use Eclipse, like most people, and simply tried running rapc on a JAR. But it turns out that these guys are incompatible on the binary level. So I had to use rapc from a command line (possible with Ant as well) to "preverify" everything.

After having some compilation errors I dug some more and found out that Java 1.3 is the most recent one supported by BlackBerry. rapc even enforces the compatibility by adding parameters to "javac": -source 1.3 -target 1.1.

Could this be the reason that the bytecode is simply incompatible to the J2ME on the phones?

Mike said...

Removing import statements doesn't make sense, because the .class files do not contain imports.
Import statements only help the compiler resolve classes, it doesn't create dependencies in itself.

Luiz Carlos Silveira said...

Just to add a little further, also referencing to some Java MIDP 2.0 classes (supposed to be present in Blackberry) will cause this error -- due to some of the classes might not be present in the device's classpath, thus rendering the loading of the referencing classes impossible, which, in the end of the chain, results in an unloadable & uninitializable main class, which triggers that error. This is true with the AMMS classess TunerControl and RdsControl -- which compile perfectly on Eclipse with MTJ but cause a initialization error when run in a Blackberry device or simulator. In this case, compiling the application with the JED tools will point out the missing classes, but if someone wants to build up a "as portable as possible single .jar application", then the solution could be to re-archteture your code to do the business via a Class.forName invokation... and handling the Exception & Error. In my case, testing with the BB Simulator, the Exception, Error or Throwable couldn't be handled by the application... or better, they could be handled, but not without the system showing an error message in the screen and asking what to do.

Anonymous said...

I just discovered the website who reviews about
Several
home based business opportunity

If you want to know more here it is
home business ideas
www.home-businessreviews.com

demaniak said...

Hi, yeah, thanks for this post ;)

Using Eclipse Galileo, with the Blackberry plugin version 1.1, the following worked for me:
1) Clean all projects (Project->Clean)

2) Package all projects again
(Project->Blackberry->Package All)

For the record, the simulator was fine, but the app failed with the verification error on the real device, cause me to thing the download was corrupt.
Re-installation did not help though, so then I figured the upload must have been bad.

Re-uploading, re-installing did not help.

So finally, I did the above, uploaded again, and boom, things worked again.

PS: I suspect I did the "clean-package" twice before it worked.

Cheers!

Anonymous said...

Thanks a lot for sharing your experience... let me add one more reason to check for....

If I try to reference .class statically, this failed for me

This didn't work:
new LineReader(Polyline.class.getResourceAsStream("polylines.txt"));

This worked:
new LineReader(new Polyline().getClass().getResourceAsStream("polylines.txt"));

Ahmed Aboulenein

Anonymous said...

Just popping in to say nice site.

tushar said...

i have 2800 lines ..... oh