3

I'm porting an app from Eclipse to Android Studio and am running into verify errors when trying to run the app on emulators with API less than 17. I'd appreciate any guidance on how to deal with this. Here's what shows up in logcat on an API 8 emulator:

12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: VFY: register1 v10 type 12, wanted 10
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: VFY:  rejecting opcode 0x70 at 0x005e
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: VFY:  rejected Lcom/zigzagworld/fonts/GlyphMetrics;.<init> (SSS[S)V
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: Verifier rejected class Lcom/zigzagworld/fonts/GlyphMetrics;

This is followed immediately (no surprise) by the app crashing with a java.lang.VerifyError. The same .apk file will run just fine on API level 17 and above. There are different code paths at API 17 and above, but the GlyphMetrics class is used at some point regardless of API level. (If different code paths can make a difference as to whether a class generates a verify error when it is loaded, someone please let me know!)

The GlyphMetrics class is a very simple container for some metric information concerning a home-brew bitmap font we use in the app:

package com.zigzagworld.fonts;

import static com.zigzagworld.fonts.Diacritics.LOWER_DIACRITIC;
import static com.zigzagworld.fonts.Diacritics.UPPER_DIACRITIC;

/**
 * Represents the layout metrics for a glyph.
 * 
 * @author Ted Hopp
 */
public final class GlyphMetrics {

    public static final short[] EMPTY_EXCLUSION = new short[0];
    public static final short[][] EMPTY_EXCLUSIONS = { EMPTY_EXCLUSION, EMPTY_EXCLUSION };
    /** The width of the glyph image, in pixels. */
    public short width;
    /** The height of the glyph image, in pixels. */
    public short height;
    /**
     * The distance in pixels between the top of the glyph image and the
     * baseline of the line. A positive value means that the top of the glyph
     * should be above the baseline of the line; a negative value means that the
     * top of the glyph should be below the baseline of the line.
     */
    public short baseline;
    /**
     * The upper and lower axes for placement of diacriticals. Each axis is the
     * distance from the left of the glyph image at which diacriticals should be
     * centered. (The formatting algorithm for the font may move diacriticals
     * from this position to avoid interference between glyphs.)
     */
    public short[] axes;
    /**
     * The upper and lower exclusion zone arrays. If there are <i>n</i> upper
     * (say) zones, the upper array has length length 2*<i>n</i>. The array has
     * the left edge of the first zone, the right edge of the first zone, the
     * left edge of the second zone, etc. The lower zone data are organized in
     * the same way.
     */
    public short[][] zones;

    public GlyphMetrics(short width, short height, short baseline, short[] layoutData) {
        this.width = width;
        this.height = height;
        this.baseline = baseline;
        axes = new short[2];
        width >>= 1; // for the rest of this, we need the half-width
        if (layoutData == null || layoutData.length == 0) {
            axes[UPPER_DIACRITIC] = axes[LOWER_DIACRITIC] = width;
            zones = EMPTY_EXCLUSIONS;
        } else {
            axes[UPPER_DIACRITIC] = layoutData[0];
            if (layoutData.length < 2) {
                axes[LOWER_DIACRITIC] = width;
            } else {
                axes[LOWER_DIACRITIC] = layoutData[1];
            }
            if (layoutData.length < 5) {
                zones = EMPTY_EXCLUSIONS;
            } else {
                int nUpper = layoutData[2] << 1;
                zones = new short[2][];
                zones[UPPER_DIACRITIC] = new short[nUpper];
                System.arraycopy(layoutData, 3, zones[UPPER_DIACRITIC], 0, nUpper);

                int lowerStart = 3 + nUpper;
                if (layoutData.length < 2 + lowerStart) {
                    zones[LOWER_DIACRITIC] = EMPTY_EXCLUSION;
                } else {
                    int nLower = layoutData[lowerStart++] << 1;
                    zones[LOWER_DIACRITIC] = new short[nLower];
                    System.arraycopy(layoutData, lowerStart, zones[LOWER_DIACRITIC], 0, nLower);
                }
            }
        }
    }
}

(The imports UPPER_DIACRITIC and LOWER_DIACRITIC are the constants 0 and 1, respectively.)

I'm building this using Android Studio 2.0 Preview 4 with Gradle plugin com.android.tools.build:gradle:2.0.0-alpha3 and JDK 1.7.0_80. Here's the build.gradle file for the .apk module:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.2'
    defaultConfig {
        applicationId "com.zigzagworld.icjl.tanachbible"
        minSdkVersion 8
        targetSdkVersion 23
        versionCode 10800310
        versionName "3.1.0"
        manifestPlaceholders = [
                appName: "App",
                v8TOCActivityName: "BaseTOCActivity",
                v8PurchaseActivityName: "PurchaseActivity",
                v17TOCActivityName: "TOCActivity",
                v17PurchaseActivityName: "PurchaseActivity",
        ]
    }
    signingConfigs {
        // redacted for this post
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            //noinspection GroovyAssignabilityCheck
            signingConfig // redacted
        }
    }
    flavorDimensions "market"
    productFlavors {
        google {
            dimension "market"
            manifestPlaceholders = [
                appName: "App_Google",
                v8TOCActivityName: "TOCActivity_Google",
                v8PurchaseActivityName: "GooglePurchaseActivity",
                v17TOCActivityName: "TOCActivity_Google",
                v17PurchaseActivityName: "GooglePurchaseActivity"
            ]
        }
        amazon {
            dimension "market"
            manifestPlaceholders = [
                appName: "App_Amazon",
                v8TOCActivityName: "BaseTOCActivity",
                v8PurchaseActivityName: "PurchaseActivity",
                v17TOCActivityName: "TOCActivity",
                v17PurchaseActivityName: "PurchaseActivity"
            ]
        }
        sideLoad {
            dimension "market"
            manifestPlaceholders = [
                    appName: "App_Unlicensed",
                    v8TOCActivityName: "BaseTOCActivity",
                    v8PurchaseActivityName: "PurchaseActivity",
                    v17TOCActivityName: "TOCActivity",
                    v17PurchaseActivityName: "PurchaseActivity"
            ]
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:support-annotations:23.1.1'
    compile project(':Tanach Data')
    googleCompile project(':Google Vending')
    amazonCompile project(':Amazon Vending')
}

The problem shows up with the debug build type, so ProGuard isn't in the picture at this point.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • maybe the answer to this link may help, this is the first time ive seen VerifyError so I thought id try to help http://stackoverflow.com/questions/100107/reasons-of-getting-a-java-lang-verifyerror – JRowan Dec 28 '15 at 02:17
  • @JRowan - I hadn't seen that particular link, but I did see many similar ones. There's nothing there that I haven't tried (cleaning the project, adding `sourceCompatibility JavaVersion.VERSION_1_7` and `targetCompatibility JavaVersion.VERSION_1_7` in a `compileOptions` block in build.gradle, checking library versions, restarting the IDE, etc.) Thanks, anyway. – Ted Hopp Dec 28 '15 at 02:28
  • oh just thought id put it up I'm still using eclipse, haven't switched over to android studio yet I thought since its still relatively new maybe it was the ide not even a programming error, sorry its not a solid lead :( – JRowan Dec 28 '15 at 02:31
  • I noticed you have com.zigzagworld.fonts; and you have com.zigzagworld.icjl.tanachbible", is one of them a library? – JRowan Dec 28 '15 at 02:35
  • might want to check the comments in this link http://stackoverflow.com/questions/32634379/verifyerror-exception-on-android-studio – JRowan Dec 28 '15 at 02:37
  • @JRowan - The font classes are just in their own package. I should mention that I'm trying to run the `sideLoad` flavor, so there are no library module dependencies in this particular .apk. Oh, and I'm not using any third-party libraries (nothing in the `libs` folder). – Ted Hopp Dec 28 '15 at 02:38
  • 1
    After spending days on this, I've just found out the downgrading the gradle plugin from 2.0.0-alpha3 to 1.5.0 makes the problem disappear. – Androiderson Dec 29 '15 at 18:01
  • @Androiderson - That did it! If you post your comment as an answer, I can accept it. – Ted Hopp Dec 29 '15 at 19:39

1 Answers1

7

After spending days on this, I've just found out that downgrading the gradle plugin from 2.0.0-alpha3 to 1.5.0 makes the problem disappear.

That's the price we pay trying to stay on the cutting edge.

Androiderson
  • 16,865
  • 6
  • 62
  • 72