26

I've tried searching around both on Google and on stackoverflow for an answer to this, but I've been unable to find anyone with the exact issue I'm having. I'm attempting to set up a continuous integration server (Bamboo, specifically) to update, build, and export an APK every time someone makes a change in source control. I'm running into the same error both on my local machine when I do every step by hand and on the server when I use the job I've set up. The error happens when I reach the dex step of the build. I've gotten the same output so far with ant debug, ant release, ant clean debug, and ant clean release. The output of the entire dex step, complete with error, is as follows:

-dex:
      [dex] input: C:\Users\...\Android\bin\classes
      [dex] input: C:\Users\...\google-play-services_lib\bin\classes.jar
      [dex] input: C:\Program Files (x86)\Android\android-sdk\tools\support\annotations.jar
      [dex] input: C:\Users\...\Android\libs\FlurryAgent.jar
      [dex] input: C:\Users\...\Android\libs\gcm.jar
      [dex] input: C:\Users\...\Android\libs\android-support-v4.jar
      [dex] input: C:\Users\...\google-play-services_lib\libs\google-play-services.jar
      [dex] Pre-Dexing C:\Users\...\google-play-services_lib\bin\classes.jar -> classes-64c0adfe92ddc950c7ab8c5002ceabf2.jar
      [dex] Pre-Dexing C:\Program Files (x86)\Android\android-sdk\tools\support\annotations.jar -> annotations-62bab95d6948a2db17bbc7976160b014.jar
      [dex] Pre-Dexing C:\Users\...\Android\libs\FlurryAgent.jar -> FlurryAgent-499d43756a3ce626a64773e6dfd5eaec.jar
      [dex] Pre-Dexing C:\Users\...\Android\libs\gcm.jar -> gcm-ae2640f44640eb4fd7b13964b65d2d70.jar
      [dex] Pre-Dexing C:\Users\...\Android\libs\android-support-v4.jar -> android-support-v4-fa30b373a3e3ba9f2cf94900a9eb42fe.jar
      [dex] Pre-Dexing C:\Users\...\google-play-services_lib\libs\google-play-services.jar -> google-play-services-9efad6e9178399c185fae6c0b6bdc4c6.jar
      [dex] Converting compiled files and external libraries into C:\Users\...\Android\bin\classes.dex...
       [dx]
       [dx] UNEXPECTED TOP-LEVEL EXCEPTION:
       [dx] com.android.dx.util.ExceptionWithContext
       [dx]     at com.android.dx.util.ExceptionWithContext.withContext(ExceptionWithContext.java:46)
       [dx]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:344)
       [dx]     at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:134)
       [dx]     at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:87)
       [dx]     at com.android.dx.command.dexer.Main.processClass(Main.java:487)
       [dx]     at com.android.dx.command.dexer.Main.processFileBytes(Main.java:459)
       [dx]     at com.android.dx.command.dexer.Main.access$400(Main.java:67)
       [dx]     at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:398)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:135)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:109)
       [dx]     at com.android.dx.command.dexer.Main.processOne(Main.java:422)
       [dx]     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:333)
       [dx]     at com.android.dx.command.dexer.Main.run(Main.java:209)
       [dx]     at com.android.dx.command.dexer.Main.main(Main.java:174)
       [dx]     at com.android.dx.command.Main.main(Main.java:91)
       [dx] Caused by: java.lang.NullPointerException
       [dx]     at com.android.dx.cf.code.ConcreteMethod.<init>(ConcreteMethod.java:87)
       [dx]     at com.android.dx.cf.code.ConcreteMethod.<init>(ConcreteMethod.java:75)
       [dx]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:247)
       [dx]     ... 23 more
       [dx] ...while processing <init> (Lcom/.../android/LocationService;)V
       [dx] ...while processing com/.../android/LocationService$1.class
       [dx]
       [dx] 1 error; aborting

For context, I'm using Ant v1.9.2 and Android build-tools v18.0.1 on a Windows machine and I haven't edited the build scripts in any way. I generated one for the app and one for the library using android update project --path . in their two directories. I also haven't tried setting it up to automatically use the proper keystore for signing yet, although to my (limited) understanding that shouldn't be necessary, at least not for a debug build with Ant.

Has anyone seen this particular issue before? Is it a problem with the generated .class file? The build files? This is my first real foray into building with Ant (I generally just let Eclipse do all the hard work for me), so I have very little to go on. Any help would be much appreciated.

Update: In case anyone was paying attention to this question, my issue seems to have resolved itself. How and why, I don't know. I tried updating the source this morning (we had a few changes in), reran android update project -p ., tried an ant clean debug, and lo and behold, it worked. As did ant release, which even signed it properly with the key I gave it. My best guess is that there was something weird in that LocationService class file, although what it was is beyond me.

Update 2: Anything I said in my first update is now invalid. I've isolated the issue, but am no closer to understanding it. This block of code is the culprit:

if (Settings.DEBUG) {
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            storeDebugNotification(AndroidUncaughtExceptionHandler.getStackTraceString(ex));
        }
    });
}

Here's where things get weird. When the Settings.DEBUG flag is true, this builds fine with ant. When it's false, it fails, giving me the error shown above. When I comment the whole thing out, it works fine with either DEBUG setting. The same goes for having the if (Settings.DEBUG) line and its curly braces commented but the body left intact, as well as commenting the body and leaving the if portion alone. So... I'm at a loss here. Something about the interaction between the if statement and the body, in this particular file, when DEBUG is false is causing problems. And the other weird part is that we have that exact same if block in another file in the app (an activity, whereas this one is a service).

Alex
  • 980
  • 8
  • 20
  • Which version of the build-tools are you using? Im using build-tools 18.0.1. and ant 1.8.4 on mac and don't get errors – Varun Aug 28 '13 at 21:23
  • I'm using build-tools version 18.0.1 and am doing this on a Windows machine. I'll update the question to include that info too. – Alex Aug 29 '13 at 13:55
  • May be just create a hello world and give it a try building with ant – Varun Aug 29 '13 at 14:39
  • A simple Hello World app worked. I created a new project in Eclipse (amusingly enough, the default activity it creates for you just displays 'Hello World!') and ran it through the same procedure (`android update project path -- .`, and `ant clean debug`). The build succeeded and I was able to install and run it without issue on my phone. – Alex Aug 29 '13 at 14:46
  • Possibly a duplicate of http://stackoverflow.com/questions/17437430/how-to-resolve-unepected-top-level-exception-in-android-studio – Nick Caballero Jan 10 '14 at 19:39

3 Answers3

39

I had the same exception while compiling a project for release. My code was:

if (BuildConfig.DEBUG) {
    myView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // Do something
        }
    });
}

Because BuildConfig.DEBUG is a constant with value false, the code in the block is recognized as dead code and removed when optimized.

The CfTranslator (Classfile Translator) wants to create a separate file for the anonymous class inside the block (SomeClass$1.class), but since it is optimized away an error will occur. I took the anonymous class outside the curly braces the problem was solved:

View.OnClickListener lClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Do something
    }
};

if (BuildConfig.DEBUG) {
    myView.setOnClickListener(lClickListener);
}

Update: Another way to solve this (described by @Ewoks in his answer below) is:

public boolean isInDeveloperMode() {
    return BuildConfig.DEBUG;
}

...

if (isInDeveloperMode()) {
    myView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // Do something
        }
    });
}
Albert-Jan Verhees
  • 2,084
  • 1
  • 16
  • 19
  • 2
    This is a very compelling explanation and I really _want_ to accept it as the answer, but there's still a piece left unexplained. In a separate file, we have literally the exact same code block (setting the handler to an anonymous class implementation within a `Settings.DEBUG` conditional), albeit with a slightly different body for the `uncaughtException()` override, and that one doesn't cause any problems. Can you think of any reason why that one would work while the other doesn't? – Alex Mar 05 '14 at 15:35
  • 2
    Worked for me as well. The weird thing is it hasn't been a problem for me until gradle 2.1 – MinceMan Oct 03 '14 at 15:27
  • wow, this was exactly it for me - an Anonymous class behind `if(BuildConfig.DEBUG)`. using Android Gradle Plugin 1.0.1 – rymo Jan 26 '15 at 20:41
  • Awesome. Worked for me. – Eidan Spiegel Nov 01 '15 at 08:48
  • I wonder if its the gradle 2.1 but we have exactly the same type block in others and its fine there only except is the component that has the inline method is a third party library, Apptimize so something in there may be raising the exception. – JPM Apr 25 '16 at 15:26
  • I don't have such BuildConfig.DEBUG in my code, and both class and method are public! Problem is still exist. – Dr.jacky Aug 08 '16 at 08:09
  • @Mr.Hyde: The error occurs if you initialize an anonymous class within a code block that is removed by optimization. A constant like BuildConfig.DEBUG set to false in an if-statement is just one example. The scope of classes and methods has nothing to do with it. If you are able to share your code, everyone here can take a closer look. – Albert-Jan Verhees Aug 24 '16 at 11:04
10

After months of fighting this exact problem, I have finally found a solution that works for me. It might not be your case. Make sure, that none of the classes you are referring to (Maybe Settings? Maybe AndroidUncaughtExceptionHandler?) is private. The Gradle is not able to handle it and cannot find the method within the class. Just change it to public (or just delete the flag to keep it default, if the class is nested), and you should be good to go.

Johny_G
  • 439
  • 6
  • 10
2

Other solution than proposed by @Albert-Jan would be to "wrap" that constant in a method. Something like

public boolean isInDeveloperMode(){ return BuildConfig.DEBUG; }

in which case it will not be "resolved" as constant by gradle and there will be no problem during build time.

Probably the most famous "exploit" of this approach would be isUserAGoat() method from UserManager class in Android SDK. There is very popular discussion here about possible uses of this method.. Enjoy ;)

Hopefully this will be useful for somebody with similar issues

Community
  • 1
  • 1
Ewoks
  • 12,285
  • 8
  • 58
  • 67