In developing an application recently, I ran into a very odd error that happened in the release build but not the debug build. The stack trace looked like this:

Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
java.lang.NullPointerException
 at java.lang.Enum$1.create(Enum.java:43)
 at java.lang.Enum$1.create(Enum.java:35)
 at libcore.util.BasicLruCache.get(BasicLruCache.java:54)
 at java.lang.Enum.getSharedConstants(Enum.java:209)
 at java.lang.Enum.valueOf(Enum.java:189)
 at com.my.app.package.b.c.a(Unknown Source)
 at com.my.app.package.b.a.onCreate(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
 at android.support.v4.app.BackStackRecord.run(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.execPendingActions(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl$1.run(Unknown Source)
 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:5455)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:525)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
 at dalvik.system.NativeStart.main(Native Method)

After a bunch of head-banging, it turns out that the android.permission.INTERACT_ACROSS_USERS_FULL part was a complete red herring. The real key in this stack trace is line 7 – the call to java.lang.Enum.valueOf. I have no explanation why the NullPointerException that was thrown should have been turned into this error by Android. If you run into a similar error, consider the possibility that the issue is an exception that has nothing to do with cross-user “stuff.”

Having dispensed with that minor piece of nonsense, let’s figure out what actually happened.

Now, any time you get something like this in a release build and the code works perfectly in the debug build, your first thought should be that the culprit is ProGuard. (Assuming you’re using it.) In my case, this is exactly what happened. A little de-obfuscation showed that line 8 above was a call to the valueOf(String) method on an enum in my code. By default, ProGuard will strip out the values and valueOf(String) methods from enums, and so the system was blowing up when something that was being called wasn’t found.

First, the solution to the problem: Include the following lines in your ProGuard configuration file:

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

This will prevent ProGuard from stripping the enum methods. Note that both methods are required – more on that in a minute. If you want to get picky, you can do this just on enums for which you use these methods, but I figure the few extra bytes in my app wasn’t going to hurt.

Now for the slightly more interesting questions:

  1. So why was it that ProGuard didn’t detect the fact that I was calling MyEnum.valueOf(String) and preserve it?
  2. Why did I have to preserve values() as well as valueOf(String)?

The answers are:

  1. Actually, ProGuard did preserve valueOf(String) – the NullPointerException was caused by values() having been stripped.
  2. Because it turns out that valueOf(String) is implemented in terms of values() in many Java implementations, but there’s some reflection involved which keeps ProGuard from seeing this.

Let’s create a simply little enum class:

public enum TestEnum
{
        A,B
}

If you compile this:

javac -classpath . TestEnum.java

and then dump the byte code

javap -c TestEnum.class

you’ll see something like this:

public final class TestEnum extends java.lang.Enum<TestEnum> {
  public static final TestEnum A;

  public static final TestEnum B;

  public static TestEnum[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[LTestEnum;
       3: invokevirtual #2                  // Method "[LTestEnum;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[LTestEnum;"
       9: areturn

  public static TestEnum valueOf(java.lang.String);
    Code:
       0: ldc_w         #4                  // class TestEnum
       3: aload_0
       4: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       7: checkcast     #4                  // class TestEnum
      10: areturn

  static {};
    Code:
       0: new           #4                  // class TestEnum
       3: dup
       4: ldc           #7                  // String A
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field A:LTestEnum;
      13: new           #4                  // class TestEnum
      16: dup
      17: ldc           #10                 // String B
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field B:LTestEnum;
      26: iconst_2
      27: anewarray     #4                  // class TestEnum
      30: dup
      31: iconst_0
      32: getstatic     #9                  // Field A:LTestEnum;
      35: aastore
      36: dup
      37: iconst_1
      38: getstatic     #11                 // Field B:LTestEnum;
      41: aastore
      42: putstatic     #1                  // Field $VALUES:[LTestEnum;
      45: return
}

Now, reading bytecode makes my hair hurt, but it turns out that this is essentially equivalent to the following Java code:

public final class TestEnum extends java.lang.Enum<TestEnum> 
{
  public static final TestEnum A;
  public static final TestEnum B;
  private static final TestEnum[] VALUES;

  public static TestEnum[] values()
  {
    return VALUES;
  }
  public static TestEnum valueOf(java.lang.String s)
  {
    return Enum.valueOf(TestEnum.class, s);
  }
  static 
  {
    A = new TestEnum("A", 0);
    B = new TestEnum("B", 0);
    VALUES = new TestEnum[2];
    VALUES[0] = A;
    VALUES[1] = B;
  }
}

The thing to notice is that valueOf(String) is actually implemented by code in the Enum class. It’s done this way, as far as I can tell, in order to be both efficient and also “lazy,” since many enums will never have valueOf(String) called. Looking at the OpenJDK source code for example, you’ll find the following:

public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 
{
  T result = enumType.enumConstantDirectory().get(name);
  if (result != null)
  {
    return result;
  }
  if (name == null)
  {
    throw new NullPointerException("Name is null");
  }
  throw new IllegalArgumentException("No enum const " + enumType +"." + name);
}

This, in turn, relies on some code in the Class class:

Map<String, T> enumConstantDirectory() 
{
  if (enumConstantDirectory == null) 
  {
    T[] universe = getEnumConstantsShared();
    if (universe == null)
    {
      throw new IllegalArgumentException(getName() + " is not an enum type");
    }
    Map<String, T> m = new HashMap<String, T>(2 * universe.length);
    for (T constant : universe)
    {
      m.put(((Enum)constant).name(), constant);
    }
    enumConstantDirectory = m;
  }
  return enumConstantDirectory; 
}

private volatile transient Map<String, T> enumConstantDirectory = null;

T[] getEnumConstantsShared() 
{
  if (enumConstants == null) 
  {
    if (!isEnum()) return null;
    try 
    {
      final Method values = getMethod("values");
      java.security.AccessController.doPrivileged
        (new java.security.PrivilegedAction() {
          public Object run() 
          {
            values.setAccessible(true);
            return null;
          }
        });
      enumConstants = (T[])values.invoke(null);
    }
    catch (InvocationTargetException ex) { return null; }
    catch (NoSuchMethodException ex) { return null; }
    catch (IllegalAccessException ex) { return null; }
  }
  return enumConstants;
}
private volatile transient T[] enumConstants = null;

The enumConstantDirectory provides the String-to-enum mapping for the individual enum class, but it is created lazily based on an array of the individual enum values returned by getEnumConstantsShared(). That method, in turn, obtains the array by calling (via reflection) the values() method on the enum class.

Twisty. But it does mean, at the end, that (assuming things are implemented this way in your JVM) that valueOf(String) won’t work if values() isn’t there. Under normal circumstances this doesn’t pose a problem, since values() is part of the guaranteed public interface of an enum class – it’s only when something like ProGuard starts running through your classes with hobnailed boots that a problem like this can occur.

So why doesn’t ProGuard just include values() any time it sees valueOf(String) called? My suspicion is that the dependency between these two methods is a JVM implementation choice, not part of the Java specification. Note that the member functions above are not public, so there’s probably no hard requirement that this functionality be implemented this way. Enum.valueOf(Class,String) is probably free to use other methods to implement valueOf(String), so ProGuard presumably doesn’t (and shouldn’t) presume that it understands enough to link the two functions.

At least, that’s my guess…

 

This post was written by Kevin Hunter, and originally appeared on Silver Bay Tech’s blog.